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

原理区别:
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="https://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
视频表明,事发当时张三在优衣库,不可能犯罪
我是张三我没有犯罪
toString

cglib动态代理更加灵活,这里直接演示基于类的代理方法 。
首先有一个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();

        }
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值