• Java动态代理和cglib动态代理


    一、何为动态代理?

        建议看动态代理前,先看看反射 点击这里

      先看一个小案例,假设有咖啡类A,B,C。有添加物类a,b,c,。现在对咖啡类进行增强。( 比如像向啡中加糖,牛奶等这个意思)。

      对一个类进行增强可以有三种方式:

      1.继承,可以直接继承父类的属性和方法,在新增自己的属性和方法。那么我们对每种咖啡进行增强,一共需要写3*3个继承类来完成。增强的对象和内容都不可变。

      2.装饰者模式,在需要增强的类中组合一个需要增强的属性。那么我们需要写三个组合咖啡类,每个类都添加一个添加物接口属性,向添加物接口传不同的实现就可以对该咖啡类进行不同的增强。增强的内容可变,但增强的对象是不可变的。

      3.动态代理,通过一个代理工厂,向其传入需要增强的咖啡类和添加物类,其自动生成一个增强后的代理类。我们只需要实现代理工厂这个类即可。

    二、java动态代理的实现

      java中有一个类Proxy,其有一个静态方法Object proxy = Proxy.newProxyInstance(ClassLoader classLoader , Class[] interfaces , InvocationHandler); 通过此方法就可以得到一个代理对象。下面说一下这三个参数。

      ClassLoader 类加载器,负责加载代理的类加载器。关于类加载器详细解答 点击这里

      Class[] 目标类所实现的接口们,用Class对象数组表示。

      Invocationhandler 处理器,当调用代理类proxy的方法时,实际上是调用处理器的 invoke()方法。下面在对invoke方法进行详解。

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

      proxy:代理对象。  method: 执行的代理对象的方法。 args: 调用代理对象的方法时传入的参数。

      下面贴代码实现

    目标类接口

    package cn.edu;
    
    public interface Waiter {
    
        public void server();
    }

    前置通知接口

    package cn.edu;
    
    public interface AdviceBefore {
    
        public void before();
    }

    后置通知接口

    package cn.edu;
    
    public interface AdviceAfter {
    
        public void after();
    }

    代理工厂

    package cn.edu;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 代理工厂,用于生产代理对象
     * 
     * @author WangHang
     *
     */
    public class ProxyFactory {
    
        private Object target;               // 目标对象
    
        private AdviceBefore adviceBefore;   // 前置通知
    
        private AdviceAfter adviceAfter;     // 后置通知
    
        // 生成代理对象核心方法
        public Object getProxyInstance() {
    
            ClassLoader loader = ProxyFactory.class.getClassLoader();    // 类加载器
            Class[] interfaces = target.getClass().getInterfaces();      // 类所实现的接口
    
            InvocationHandler h = new InvocationHandler() {              // 处理器
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (adviceBefore != null) {
                        adviceBefore.before();                           // 调用前置通知
                    }
                    Object result = method.invoke(target, args);         // 调用目标方法
                    if (adviceAfter != null) {                           // 调用后置通知
                        adviceAfter.after();
                    }
                    return result;
                }
            };
    
            Object proxy = Proxy.newProxyInstance(loader, interfaces, h); // 通过给定的三个参数生成动态代理对象
            return proxy;                                                 // 返回代理对象
        }
    
        public AdviceBefore getAdviceBefore() {
            return adviceBefore;
        }
    
        public void setAdviceBefore(AdviceBefore adviceBefore) {
            this.adviceBefore = adviceBefore;
        }
    
        public AdviceAfter getAdviceAfter() {
            return adviceAfter;
        }
    
        public void setAdviceAfter(AdviceAfter adviceAfter) {
            this.adviceAfter = adviceAfter;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
    }

    测试,接口的实现用的匿名内部类

    package cn.edu;
    
    import org.junit.Test;
    
    public class ProxyTest {
    
        @Test
        public void fun() {
            Waiter waiter = new Waiter() {                         //生成目标对象
                @Override
                public void server() {
                    System.out.println("服务中。。。");
                }
            };
            
            AdviceBefore before = new AdviceBefore() {             //生成前置通知
                @Override
                public void before() {
                    System.out.println("欢迎光临!");
                }
            };
            
            AdviceAfter after = new AdviceAfter() {
                @Override
                public void after() {
                    System.out.println("谢谢光临!");                //生成后置通知
                }
            };
            
            ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
            
            proxyFactory.setTarget(waiter);                          //设置目标对象
            proxyFactory.setAdviceBefore(before);                    //设置前置通知
            proxyFactory.setAdviceAfter(after);                      //设置后置通知
            
            Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //获得代理对象
            
            proxy.server();                                          //调用目标对象的方法
        }
        
    }

    运行结果:

    三、cglib动态代理的实现

       java动态代理的实现要求目标类实现接口,如果没有接口就无法完成动态代理。cglib(Code Genaration Liarbry)是一个强大的Code生成类库 ,它可以在程序运行期间扩展Java类。它不要求目标类实现接口,它采用的是继承的方式来扩展目标类。

      下面用cglib实现代理,其余类不用变,只需更改代理工厂,并且给Waiter添加一个实现类WaiterImpl,cglib代理是需要类的,用匿名类是会报错的。更改的部分如下。

    Waiter实现类

    package cn.edu.cglibProxy;
    
    public class WaiterImpl implements Waiter {
    
        @Override
        public void server() {
            // TODO Auto-generated method stub
            System.out.println("服务中。。。");
        }
    
    }

    代理工厂类

    package cn.edu.cglibProxy;
    
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    /**
     * 代理工厂,用于生产代理对象
     * 
     * @author WangHang
     *
     */
    public class ProxyFactory {
    
        private Object target;             // 目标对象
    
        private AdviceBefore adviceBefore; // 前置通知
    
        private AdviceAfter adviceAfter;   // 后置通知
    
        // 生成代理对象核心方法
        public Object getProxyInstance() {
    
            Enhancer enhancer = new Enhancer();
            
            enhancer.setSuperclass(target.getClass());
            
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    adviceBefore.before();
                    Object result = method.invoke(target, args);
                    adviceAfter.after();
                    return result;
                }
            });
            Object proxy = enhancer.create();
            return proxy;            // 返回代理对象
        }
    
        public AdviceBefore getAdviceBefore() {
            return adviceBefore;
        }
    
        public void setAdviceBefore(AdviceBefore adviceBefore) {
            this.adviceBefore = adviceBefore;
        }
    
        public AdviceAfter getAdviceAfter() {
            return adviceAfter;
        }
    
        public void setAdviceAfter(AdviceAfter adviceAfter) {
            this.adviceAfter = adviceAfter;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
    }

    测试类

    package cn.edu.cglibProxy;
    
    import org.junit.Test;
    
    public class ProxyTest {
    
        @Test
        public void fun() {
            
            Waiter waiter = new WaiterImpl();
            
            AdviceBefore before = new AdviceBefore() {             //生成前置通知
                @Override
                public void before() {
                    System.out.println("欢迎光临!");
                }
            };
            
            AdviceAfter after = new AdviceAfter() {
                @Override
                public void after() {
                    System.out.println("谢谢光临!");                //生成后置通知
                }
            };
            
            ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
            
            proxyFactory.setTarget(waiter);                          //设置目标对象
            proxyFactory.setAdviceBefore(before);                    //设置前置通知
            proxyFactory.setAdviceAfter(after);                      //设置后置通知
            
            Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //获得代理对象
            
            proxy.server();                                          //调用目标对象的方法
        }
        
    }

    测试结果

    四、总结  

      通过上面的两个例子,可以体会到动态代理的优势。静态代理是由程序员手动编写好源代码,在程序运行时已经存在了class文件,而动态代理则是在运行时根据需要动态生成的,不仅减少了工作量,使用时也更加灵活。

  • 相关阅读:
    第一周学习进度
    四则运算
    添加课程
    继承和多态的动手动脑
    String 方法
    【CoreData】分页查询和模糊查询
    【CoreData】表之间的关联
    代码创建storyboard
    UIWindows 使用注意
    UIApplicationDelegate
  • 原文地址:https://www.cnblogs.com/wanghang-learning/p/9160557.html
Copyright © 2020-2023  润新知