美文网首页
Java进阶之JDK动态代理与Cglib动态代理

Java进阶之JDK动态代理与Cglib动态代理

作者: mayiwoaini | 来源:发表于2018-11-19 14:54 被阅读11次

    转自:https://blog.csdn.net/janice0529/article/details/42884019

    一、动态代理概述

    与静态代理对照, 动态代理类的字节码是在程序运行时由Java反射机制动态生成。
    注意:
    1、AspectJ是采用编译时生成AOP代理类,具有更好的性能,但是需要使用特定的编译器进行处理
    2、Spring AOP采用运行时生成AOP代理类,无需使用特定编译器进行处理,但是性能相对于AspectJ较差

    二、JDK动态代理 [对有实现接口的对象做代理]

    1.JDK动态代理中,需要了解的两个重要类或接口[InvocationHandler和Proxy]
    ① InvocationHandler接口

    public interface InvocationHandler { 
        public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
    }
    

    参数说明:
    Object proxy:指被代理的对象
    Method method:我们所要调用被代理对象的某个方法的Method对象
    Object[] args:被代理对象某个方法调用时所需要的参数
    可以将InvocationHandler接口的子类想象成一个代理的最终操作类。
    说明:每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类(Proxy)的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。同时在invoke的方法里 我们可以对被代理对象的方法调用做增强处理(如添加事务、日志、权限验证等操作)。

    ② Proxy类

    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,该类常用的调用方法如下: 图1:Proxy类方法概要 newProxyInstance方法参数说明如下:

    ClassLoader loader:类加载器,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    Class<?>[] interfaces:得到被代理类全部的接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口,这样我就能调用这组接口中的方法了
    InvocationHandler h:得到InvocationHandler接口的子类实例

    2、JDK动态代理代码示例:
    首先我们定义了一个Subject类型的接口:Subject.java

    public interface Subject {
        public void visit();
    }
    

    接着定义一个接口的实现类,这个类就是我们示例中的被代理对象:RealSubject.java

    /**
     * 被代理类
     * @author lvzb.software@qq.com
     *
     */
    public class RealSubject implements Subject {
     
        @Override
        public void visit() {
             System.out.println("I am 'RealSubject',I am the execution method");
        }
     
    }
    

    第三步 定义一个动态代理类(必须要实现 InvocationHandler 这个接口):DynamicProxy.java

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    /**
     * JDK动态代理类
     * @author lvzb.software@qq.com
     *
     */
    public class DynamicProxy implements InvocationHandler {
     
        // 我们要代理的真实对象(委托对象)
        private Object subject;
        
        // 构造方法,给我们要代理的真实对象赋初值
        public DynamicProxy(Object obj){
            this.subject = obj;
        }
        
        @Override
        public Object invoke(Object object, Method method, Object[] args)
                throws Throwable {
            // 在代理真实对象操作前 我们可以添加一些自己的操作
            System.out.println("before proxy invoke");
            
            // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
            method.invoke(subject, args);
            
            // 在代理真实对象操作后 我们也可以添加一些自己的操作
            System.out.println("after proxy invoke");
            return null;
        }
     }
    

    最后代理测试类:Client.java

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
     
    public class Client {
     
        public static void main(String[] args) {
            // 我们要代理的真实对象
            Subject realSubject = new RealSubject();
            // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象调用方法的
            InvocationHandler handler = new DynamicProxy(realSubject);
            /*
             * 通过Proxy的newProxyInstance方法来动态创建我们的代理对象,我们来看看其三个参数<br/>
             * 参数一:我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象<br/>
             * 参数二:我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了<br/>
             * 参数三:我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
             */
            Subject proxyInstance = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), 
                    RealSubject.class.getInterfaces(), 
                    handler);
            
            System.out.println(proxyInstance.getClass().getName());
            proxyInstance.visit();
     
        }
     
    }
    

    运行->控制台输出结果如下:

    com.sun.proxy.$Proxy0
    before proxy invoke
    I am 'RealSubject',I am the execution method
    after proxy invoke
    

    三、Cglib(Code Generation Library)动态代理 [对没有实现接口的普通类做代理]
    1、概述:
    Cglib是一个优秀的动态代理框架,它的底层使用ASM(JAVA字节码处理框架)在内存中动态的生成被代理类的子类。使用CGLIB即使被代理类没有实现任何接口也可以实现动态代理功能。但是不能对final修饰的类进行代理。
    2、原理:
    通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
    <JDK动态代理与CGLib动态代理均是实现Spring AOP的基础>
    3、使用:
    使用Cglib前需要导入以下两个jar文件:
    asm.jar – Cglib的底层实现。
    [cglib包的底层是使用字节码处理框架ASM来转换字节码并生成新的类,所以cglib包要依赖于asm包]
    cglib.jar - Cglib的核心jar包。
    4、Cglib动态代理代码示例:
    首先定义一个没有实现接口的代理委托类:CglibRealSubject.java

    /**
     * 没有实现接口的代理委托类
     * @author lvzb.software@qq.com
     *
     */
    public class CglibRealSubject{
     
        public void visit() {
            System.out.println("I am 'RealSubject',I am the execution method");
        }
     
    }
    

    接着定义一个Cglib动态代理类: CglibDynamicProxy.java

    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    /**
     * 使用cglib动态代理
     * @author lvzb.software@qq.com
     *
     */
    public class CglibDynamicProxy implements MethodInterceptor {
     
        private Object target;
        
        /**
         * 创建代理对象
         * @param target 被代理的对象
         * @return
         */
        public Object getProxyInstance(Object target){
            this.target = target;
            // 声明增强类实例
            Enhancer enhancer = new Enhancer(); 
            // 设置被代理类字节码,CGLIB根据字节码生成被代理类的子类
                    enhancer.setSuperclass(this.target.getClass());  
                    // 设置要代理的拦截器,回调函数,即一个方法拦截   new MethodInterceptor()
                    enhancer.setCallback(this); 
                    // 创建代理对象 实例 
                    return enhancer.create();  
        }
        
        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                MethodProxy proxy) throws Throwable {
            // 在代理真实对象操作前 我们可以添加一些自己的操作
            System.out.println("前置代理,增强处理");
            
            proxy.invokeSuper(obj, args);
            
            // 在代理真实对象操作后 我们也可以添加一些自己的操作
            System.out.println("后置代理,增强处理");
            return null;
        }
     
    }
    

    相关文章

      网友评论

          本文标题:Java进阶之JDK动态代理与Cglib动态代理

          本文链接:https://www.haomeiwen.com/subject/fdtafqtx.html