简介
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
JDK动态代理
代理步骤:
(1)定义一个事件管理器类实现invocationHandle接口,并重写invoke(代理类,被代理的方法,方法的参数列表)方法。
(2)实现被代理类及其实现的接口
(3)调用Proxy.newProxyInstance(类加载器,类实现的接口,事务处理器对象);生成一个代理实例。
(4)通过该代理实例调用方法。
代码实现:
JDK动态代理,为接口实现的对象创建代理。具体详见源码
//1. 抽象主题
public interface Moveable {
void move() throws Exception;
}
//2. 真实主题
public class Car implements Moveable {
public void move() throws Exception {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中…");
}
}
//3.事务处理器
public class TimeHandler implements InvocationHandler {
private Object target;
// 实现代理类
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* 参数:
*proxy 被代理的对象
*method 被代理对象的方法
*args 方法的参数
*Object 方法返回值
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶…");
method.invoke(target, args);
long stopTime = System.currentTimeMillis();
System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");
return null;
}
}
//测试类
public class Test {
public static void main(String[] args) throws Exception{
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/**
*loader 类加载器
*interfaces 被代理类实现的接口
*h InvocationHandler 事物处理器
*/
Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
m.move();
}
}
cglib动态代理
针对于非接口实现的对象,创建的是类的代理类,然后由代理类创建对象
写法一:
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//1.具体主题
public class Train{
public void move(){
System.out.println("火车行驶中…");
}
}
//2.生成代理
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* 参数:
* obj 目标实例对象
* method 目标方法的反射对象
* args 方法的参数
* proxy 代理类的实例
*/
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;
}
}
//3.测试
public class Test {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Train t = (Train) proxy.getProxy(Train.class);
t.move();
}
}
写法二:
import java.lang.reflect.Method;
import dc.com.dao.CustomerDaoImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class BeanFactory {
public static CustomerDaoImpl getBean() {
// 准备目标类
final CustomerDaoImpl goodsDao = new CustomerDaoImpl();
// 创建切面类实例
final Aspect myAspect = new Aspect();
// 生成代理类,CGLIB在运行时,生成指定对象的子类,增强
Enhancer enhancer = new Enhancer();
// 确定需要增强的类
enhancer.setSuperclass(goodsDao.getClass());
// 添加回调函数
enhancer.setCallback(new MethodInterceptor() {
// intercept 相当于 jdk invoke,前三个参数与 jdk invoke—致
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
myAspect.myBefore(); // 前增强
Object obj = method.invoke(goodsDao, args); // 目标方法执行
// 或者这种写法 Object obj = methodProxy.invokeSuper(proxy, args);
myAspect.myAfter(); // 后增强
return obj;
}
});
// 创建代理类
CustomerDaoImpl goodsDaoProxy = (CustomerDaoImpl) enhancer.create();
return goodsDaoProxy;
}
}