CGlib和JDK动态代理
JDk动态代理基于接口实现
package com.xin.demo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
//代理模式:基于JDK反射机制:(Poxy类+InvocationHandler接口)
//通过接口实现:目标对象要实现接口
/*
*Mybatis框架底层,每次调用Mapper映射器时,使用该Mappper映射器的动态代理对象调用目标方法
*MapperProxyFactory(Proxy类创建Mapper的代理对象)
*MapperProxy(是InvocationHandler接口的实现类)
*
*/
public class JdkProxyFactory implements InvocationHandler{
//定义目标对象
private Object target;
//构造方法传入目标对象
public JdkProxyFactory(Object target) {
super();
this.target = target;
}
//创建代理对象
public Object createProxy() {
//获取目标对象Class对象
Class targetClass = target.getClass();
//参数1:目标对象的Class对象的类加载器
//参数2:目标对象实现的接口(数组)
//参数3:InvocationHandler接口的实现类也就是当前类,代理对象调用目标方法时就到参数所在对象的invoke方法
Object newProxy = Proxy.newProxyInstance(targetClass.getClassLoader()
, targetClass.getInterfaces()
, this);
//返回代理对象
return newProxy;
}
//proxy时当前产生的代理对象
//method:传入的目标方法
//args:目标方法的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("***********增强功能**************");
System.out.println("方法参数:"+Arrays.toString(args));
System.err.println("目标方法:"+method);
System.err.println("代理方法:");
//完成目标方法的调用
//method.invoke(target, args)参数:目标对象,目标对象方法参数
Object invoke = method.invoke(target, args);
return invoke;
}
}
CGlib动态代理基于接口实现
package com.xin.demo.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//代理模式:基于Cglib实现(Enhancer类+MethodInterceptor接口)
//基于继承实现
public class CglibProxyFactory implements MethodInterceptor{
private Object target;
public CglibProxyFactory(Object target) {
super();
this.target = target;
}
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());//传入目标类的Class对象,会自动寻找目标类父类
//设置回调对象:当代理对象调用目标方法时,会执行对象的intercept方法
enhancer.setCallback(this);//传入实现CallBack的实现类,当前类实现了MethodInterceptor,MethodInterceptor实现了CallBack
Object create = enhancer.create();//创建代理对象
return create;//返回代理对象
}
//当目标对象调用方法时,会将方法传入intercept中,method是传入目标方法,arg2是目标方法参数
@Override
public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("增强###################################");
//执行标方法
Object invoke = method.invoke(target, arg2);
System.out.println("增强*****************************************");
//方法返回值
return invoke;
}
}
两种代理的测试
package com.xin.demo.proxy;
import com.xin.dao.DemoDAOImpl;
import com.xin.dao.IDemoDAO;
//代理
public class DemoProxy implements IDemoDAO{
private IDemoDAO idemo=new DemoDAOImpl();
@Override
public void executeInsert() {
System.out.println("【增强】");
idemo.executeInsert();
}
@Override
public void executeUpdate() {
System.out.println("【增强】");
idemo.executeUpdate();
}
}
JDK和CGLIB动态代理的区别
JDK代理使用的是反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLIB代理使用字节码处理框架asm,对代理对象类的class文件加载进来,通过修改字节码生成子类。
JDK创建代理对象效率较高,执行效率较低;
CGLIB创建代理对象效率较低,执行效率高。
JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类;
CGLIB则使用的继承机制,针对类实现代理,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,因为是继承机制,不能代理final修饰的类。
JDK代理是不需要依赖第三方的库,只要JDK环境就可以进行代理,需要满足以下要求:
1.实现InvocationHandler接口,重写invoke()
2.使用Proxy.newProxyInstance()产生代理对象
3.被代理的对象必须要实现接口
CGLib 必须依赖于CGLib的类库,需要满足以下要求:
1.实现MethodInterceptor接口,重写intercept()
2.使用Enhancer对象.create()产生代理对象