• 动态代理和AOP


    之前说过了我对IOC的理解,这篇文章说以下我对动态代理和基本的对AOP的理解。

    所谓动态代理就是,在运行时,动态创建实现了一组指定接口的实现类对象。

    比如有:

    interface A {
    }
    interface B{
    }

    即:

    Object o = 方法(new Class[] {A.class,B.class}) ,

    o实现了A和B两个接口

    但是我们在运行时是无法写源代码来进行这个类的创建。

    这时候我们需要用到Proxy类下的newProxyInstance()方法。

    1.newProxyInstance()方法

    Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);

    1. 方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!

    参数;

    1. ClassLoader:类加载器!

      * 它是用来加载器的,把.class文件加载到内存,形成Class对象!

    2. Class[] interfaces:指定要实现的接口们

    3. InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。

    我们来看这个方法的使用方式:

    public class Demo1 {
        @Test
        public void fun1() {
            /* 1. ClassLoader
             * 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象!
             * 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader!!!
             * 2. Class[] interfaces
             * 它是要实现的接口们
             * 3. InvocationHandler
             * 它是调用处理器 
             * 代理对象的实现的所有接口中的方法,内容都是调用InvocationHandler的invoke()方法。
             */
            ClassLoader loader = this.getClass().getClassLoader();//把当前使用的这个类的类加载器给代理对象使用
            InvocationHandler h = new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    System.out.println("动态代理!");
                    return "xxx";
                }
            };
            // 使用三大参数创建代理对象!!!
            Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
            // 强转成A和B类型 
            A a = (A) o;
            B b = (B) o;
            
            Object result = a.aaa("hello", 100);
            System.out.println(result);
        }
    }

    和两个接口:

    interface A {
        public void a();
        public void aa();
        public Object aaa(String s, int i);
    }
    
    interface B {
        public void b();
        public void bb();
    }

    将o强转成A和B类型后,可以调用A接口中的方法和B接口中的方法,但是不论调用什么方法最中都是调用的InvocationHandler中的 invoke方法即打印输出动态代理!但是除此之外所有的Object中的非本地方法都是输出这个结果,这是因为Native方法不是用Java编写的所有就不需要管这个部分。

    2.InvocationHandler接口其中只有invoke一种方法:

    public Object invoke(Object proxy, Method method, Object[] args);

    这个invoke()方法在调用代理对象所实现接口中的方法时被创建

    * Object proxy:当前对象,即代理对象!在调用谁的方法!

    * Method method:当前被调用的方法(目标方法)

    * Object[] args:实参!

    当在调用这个方法时,其对应关系为:

    3.用动态代理进行增强

    假设一个接口Waiter以及其一个实现类,该实现类提供一个方法:

    public interface Waiter {
        // 服务
        public void serve();
    }
    public class ManWaiter implements Waiter {
        public void serve() {
            System.out.println("服务中...");
        }
    }

    为了在调用ManWaiter的serve方法之外添加其他能力,就需要用动态代理来实现这样的功能:

    public class Demo2 {
        @Test
        public void fun1() {
            Waiter manWaiter = new ManWaiter();//目标对象
            /*
             * 给出三个参数,来创建方法,得到代理对象
             */
            ClassLoader loader = this.getClass().getClassLoader();
            Class[] interfaces = {Waiter.class};
            InvocationHandler h = new WaiterInvocationHandler(manWaiter);//参数manWaiter表示目标对象
            // 得到代理对象,代理对象就是在目标对象的基础上进行了增强的对象!
            Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h);
            
            waiterProxy.serve();//前面添加“您好”, 后面添加“再见”
        }
    }
    
    class WaiterInvocationHandler implements InvocationHandler {
        private Waiter waiter;//目标对象
        
        public WaiterInvocationHandler(Waiter waiter) {
            this.waiter = waiter;
        }
    }
    
    public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("您好!");
            this.waiter.serve();//调用目标对象的目标方法
            System.out.println("再见!");
            return null;
        }
    }

    我们在invoke 中实现了对对象能力的增强,这就是使用动态代理的能力。

    4.在之前的基础上,为了提升动态代理的能力,实现了让目标对象和增强都是可以切换的,在创建目标对象之外,还需要查创建增强对象接口,

    public interface BeforeAdvice {
        public void before();
    }
    
    public interface AfterAdvice {
        public void after();
    }

    创建一个代理工厂,ProxyFactory:

    /**
     * 1. 创建代理工厂
     * 2. 给工厂设置三样东西:
     *   * 目标对象:setTargetObject(xxx);
     *   * 前置增强:setBeforeAdvice(该接口的实现)
     *   * 后置增强:setAfterAdvice(该接口的实现)
     * 3. 调用createProxy()得到代理对象
     *   * 执行代理对象方法时:
     *   > 执行BeforeAdvice的before()
     *   > 目标对象的目标方法
     *   > 执行AfterAdvice的after()
     * @author cxf
     *
     */
    public class ProxyFactory {
        private Object targetObject;//目标对象
        private BeforeAdvice beforeAdvice;//前置增强
        private AfterAdvice afterAdvice;//后置增强
        
        
        /**
         * 用来生成代理对象
         * @return
         */
        public Object createProxy() {
            /*
             * 1. 给出三大参数
             */
            ClassLoader loader = this.getClass().getClassLoader();
            Class[] interfaces = targetObject.getClass().getInterfaces();
            InvocationHandler h = new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    /*
                     * 在调用代理对象的方法时会执行这里的内容
                     */
                    // 执行前置增强
                    if(beforeAdvice != null) {
                        beforeAdvice.before();
                    }
                    
                    Object result = method.invoke(targetObject, args);//执行目标对象的目标方法
                    // 执行后置增强
                    if(afterAdvice != null) {
                        afterAdvice.after();
                    }
                    
                    // 返回目标对象的返回值
                    return result;
                }
            };
            /*
             * 2. 得到代理对象
             */
            Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
            return proxyObject;
        }
    }

    当我们使用代理工厂的时候就可以这样做来实现对象的增强:

    public void fun1() {
            ProxyFactory factory = new ProxyFactory();//创建工厂
            factory.setTargetObject(new ManWaiter());//设置目标对象
            factory.setBeforeAdvice(new BeforeAdvice() {//设置前置增强
                public void before() {
                    System.out.println("您好!");
                }
            });
            
            factory.setAfterAdvice(new AfterAdvice() {//设置后置增强
                public void after() {
                    System.out.println("再见!");
                }
            });
            
            Waiter waiter = (Waiter)factory.createProxy();
            waiter.shouQian();
        }

    动态代理类似于装饰者模式,但是比装饰者模式更加灵活,动态代理的作用就是最终实现AOP(面向切面编程)。面向切面编程中,切面是一种新的模块机制,用来描述分散在对象,类或者方法中的横切关注点,横切关注点是会影响到整个应用程序关注功能,于正常的业务是正交的,这些横切关注点可以是事务,日志和安全性等其他功能。

  • 相关阅读:
    简易自制线程池(备忘)
    大数据量的删除过程查看
    收集书籍备忘
    6月12日C代码
    fseek()
    区分int *p[4]与int (*p)[4]
    常用的字符串处理函数 C语言
    6月11日
    C学习代码
    文件读取 C语言
  • 原文地址:https://www.cnblogs.com/winterfells/p/8616737.html
Copyright © 2020-2023  润新知