Java动态代理机制介绍(jdk和cglib的区别)

来源:互联网 发布:android ui布局优化 编辑:程序博客网 时间:2024/05/29 04:39

原理区别:
Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
具体区别代码分析jdk和cglib原理:
 Jdk动态代理:Proxy.newProxyInstance(classLoader, interfaces, InvocationHandler)
  要在classLoader里去找interfaces,如果也加载进来了才能继续执行,并且用ProxyGenerator动态生成了一个代理类的字节码文件(使用了缓存技术,只需要生成一次),然后用classLoader将这个字节码文件加载进来。这就是classLoader的作用。
现在举一个例子 :JDK的动态代理是基于 接口的,我们首先创建一个接口Court.java,定义一个打官司的方法 。具体代码如下:

public interface Court {    void doCourt();}

定义一个Person类Person.java

public class People implements Court{    private String name;    public People() {        super();        // TODO Auto-generated constructor stub    }    public People(String name) {        super();        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void doCourt() {        // TODO Auto-generated method stub        System.out.println("我是"+name+"我没有犯罪");    }}

最后创建一个测试类TestDemo.java

package com.yida.ProxyDemo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.junit.Test;public class TestDemo {    /**     * jdk提供的动态代理是基于接口实现的,给接口的所有     * 实现类生产代理对象     */    @Test    public void test01(){        final Court c = new People("张三");//匿名内部类不能访问外部类方法中的局部变量,除非该变量被声明为final类型        Object oc = Proxy.newProxyInstance(//得到代理对象                 TestDemo.class.getClassLoader(), //应用类加载器都可以                c.getClass().getInterfaces(),//被代理对象所有类的实现类                new InvocationHandler() {                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        // TODO Auto-generated method stub                        String name = method.getName();                        System.out.println(name);                        if(name.equals("doCourt")){                            System.out.println("视频表明,事发当时张三在优衣库,不可能犯罪");                            return method.invoke(c, args);                        }else{                            return method.invoke(c, args);                        }                    }                });        Court cc = (Court) oc;        cc.doCourt();        cc.toString();    }}输出结果为:<img src="http://img.blog.csdn.net/20170923232008295?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlrZW1lYmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="30%" height="auto" alt=""/>好像图片不好使,直接把地址复制到地址栏回车就可以看到了,这里我就复制下结果吧!结果是:doCourt视频表明,事发当时张三在优衣库,不可能犯罪我是张三我没有犯罪toStringcglib动态代理更加灵活,这里直接演示基于类的代理方法 。首先有一个Person类Person.java,定义了一个打官司的方法doCourt,代码如下:
package com.yida.cglib;public class Person {    public void doCourt(){        System.out.println("打官司----------");    }}

我们想代理这个对象必须需要实现方法拦截器接口MethodInterceptor,创建CglibPerson.java,代码如下:

package com.yida.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * 实现接口: 方法拦截器 * 1.在执行person里面的方法时,执行流程,首先找方法拦截器, *   执行拦截器的方法 *   person.doCourt()方法----->拦截器的方法:intercept()方法 * 2.在这里通过EnHanser对象去给Person生成代理对象 *  */@SuppressWarnings("all")//先去除所有黄线警告public class CglibPerson implements MethodInterceptor{    //创建enhanser对象     public Enhancer en = new Enhancer();     //给person生成代理对象    public  Object getProxy(Class clazz){// Person.class         //引入父类:Person ,生成代理对象不就是Person的子类(子类就是代理对象)         en.setSuperclass(clazz);         en.setCallback(this);         //得到了代理对象         Object obj = en.create();         return obj;     }    /**     * 参数1 : 类对象,person     * 参数2 : 类里面的方法对象,doCourt方法对象     * 参数3: args 方法里面的参数     * 参数4: 代理方法对象     * MethodProxy@e582a85:      * methodProxy: 代理对象的方法,而不是执行父类的Person的方法method     */    public Object intercept(Object obj , Method method, Object[] args,            MethodProxy methodProxy) throws Throwable {        System.out.println("你家里有背景,你脸白!!");        //Object obj1 = method.invoke(obj,args);        //返回的代理对象        Object obj1 = methodProxy.invokeSuper(obj, args);// method.invoke(obj,args);        return obj1;    }}

最后我们看效果吧!就直接写一个主方法来测试了,DemoCglib.java如下:

package com.yida.cglib;/** * p代理对象: null * 在拦截方法里面: *  * 不执行这个方法:method.invoke(obj,args);而是: methodProxy.invokeSuper(obj, args); * 代理对象: Person$$EnhancerByCGLIB$$45cef45a@48b49e4 * 代理对象就是Person的子类 * @author Administrator * */public class DemoCglib {        public static void main(String[] args) {            //1.得到代理对象            CglibPerson cp = new CglibPerson();            // proxy :             Object proxy = cp.getProxy(Person.class);            //2.类型转换            //cn.itheima.cg.Person$$EnhancerByCGLIB$$45cef45a@48b49e4            Person  p = (Person) proxy;            //System.out.println(p);            p.doCourt();        }}

程序执行的结果是:
你家里有背景,你脸白!!
打官司———-!

原创粉丝点击