您的位置:首页 > 编程语言 > Java开发

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

2017-09-23 23:12 495 查看
原理区别:

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();

}
}


程序执行的结果是:

你家里有背景,你脸白!!

打官司———-!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: