1、使用 cglib 代理
使用 cglib 代理完成上一章 静态代理的事务管理的功能。
沿用上一章的几个类:
- 实体类:User
- 接口:UserService
- 接口实现类: UserServiceImpl
引入依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
编写cglib 工厂代理类:
package com.lcy.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyFactory implements MethodInterceptor {
// 1 持有一个目标对象(被代理对象)
private Object target;
public ProxyFactory(){}
// 2 注入目标对象
public ProxyFactory(Object target){
this.target = target;
}
// 3 返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
// 3.1 创建工具类
Enhancer enhancer = new Enhancer();
// 3.2 设置父类
enhancer.setSuperclass(target.getClass());
// 3.3 设置回调函数
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 重写 intercept 方法,该方法会调用目标对象的方法
* @param o
* @param method
* @param args
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理 。。。开启事务" );
Object result = method.invoke(target, args);
System.out.println("cglib代理 。。。提价事务" );
return result;
}
}
测试方法:
package com.lcy.test;
import com.lcy.model.User;
import com.lcy.proxy.cglib.ProxyFactory;
import com.lcy.service.UserService;
import com.lcy.service.impl.UserServiceImpl;
public class CgLibProxyFactoryTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ProxyFactory proxy = new ProxyFactory(userService);
UserService userServiceProxy = (UserService)proxy.getProxyInstance();
userServiceProxy.save(new User(5,"赵子龙"));
System.out.println(userServiceProxy.getClass());
}
}
程序运行结果:
2、JDK代理与cglib代理对比
相同点:
- 都不需要实现 目标对象的接口
- 代理工厂都需要持有 目标对象实现类对象(都需要往代理工厂注入目标对象)
- 可以代理多个目标对象,比如 proxy代理是提交事务处理的类,UserServiceImp 需要事务处理,就把UserServiceImp 对象注入到 proxy代理。调用相应的方法就能产生代理对象。其他的如 DeptServiceImp 需要事务处理,也是和 UserServiceImp 一样的操作。
不同点:
1、JDK 的动态代理是实现 InvocationHandler 接口,重写 invoke 方法
2、cglib的动态代理是实现 MethodInterceptor 接口,重写 intercept 方法
3、JDK 动态代理 采用的是 反射生成的代理对象
4、cglib 动态代理 底层是修改了字节码
5、cglib 不能对 final、static 声明的方法进行代理
6、cglib 不需要目标对象实现接口,jdk代理是需要目标对象实现接口,详情见下图: