说起动态代理,首先想到的就是 Spring
,在 Spring
中有两种动态代理方式: JDK
动态代理和 Cglib
动态代理。
JDK
动态代理是 Java
本来就有的一种代理方式,关键类是 java.lang.reflect.InvocationHandler
。
我们先创建一个简单的 SpringBoot
项目,然后创建 UserService
和 UserServiceImpl
。
public interface UserService {
void add();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加用户...");
}
}
复制代码
这个 UserServiceImpl
就是我们要代理的类,它继承了 UserService
接口,所以使用 JDK
动态代理。
然后我们创建一个简单的类来模拟事务处理
@Component
public class TransactionManager {
public void begin() {
System.out.println("创建事务");
}
public void commit() {
System.out.println("提交事务");
}
public void rollback() {
System.out.println("回滚事务");
}
}
复制代码
最后要创建代理器了,首先要实现 java.lang.reflect.InvocationHandler
这个接口,复写 invoke
方法。
@Component
public class JdkProxyHandler implements InvocationHandler {
/**
* 事务处理器
*/
@Resource
private TransactionManager transcationManager;
@Setter
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object ret = null;
try {
//模拟事务开始
transcationManager.begin();
ret = method.invoke(target, args);
//模拟事务提交
transcationManager.commit();
} catch (Exception e) {
//模拟事务回滚
transcationManager.rollback();
e.printStackTrace();
}
return ret;
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(
//类加载器
this.getClass().getClassLoader(),
//为哪些接口做代理
target.getClass().getInterfaces(),
//增强对象
this);
}
}
复制代码
首先我们把代理器和要代理的对象注入进来,通过 jdkProxyHandler.getProxy
方法得到代理对象。
@SpringBootTest
class Springdemo1ApplicationTests {
@Resource
private JdkProxyHandler jdkProxyHandler;
@Resource
private UserService userService;
@Test
public void testJdkProxy() throws Exception {
//设置要代理的对象
jdkProxyHandler.setTarget(userService);
//得到代理对象
UserService proxy = jdkProxyHandler.getProxy();
//代理对象执行方法
proxy.add();
}
}
复制代码
我们也要实现一个接口 InvocationHandler
,不过这个接口是 Spring
提供的 org.springframework.cglib.proxy.InvocationHandler
。复写其中的 invoke
方法。
获取代理类的方式不一样,使用 org.springframework.cglib.proxy.Enhancer#create()
这个方法获取。
@Component
public class CglibProxyHandler implements InvocationHandler {
/**
* 事务处器
*/
@Resource
private TransactionManager transcationManager;
@Setter
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object ret = null;
try {
//模拟事务开始
transcationManager.begin();
ret = method.invoke(target, args);
//模拟事务提交
transcationManager.commit();
} catch (Exception e) {
//模拟事务回滚
transcationManager.rollback();
e.printStackTrace();
}
return ret;
}
public <T> T getProxy() {
//增强类
Enhancer hancer = new Enhancer();
//对哪一个父类增强
hancer.setSuperclass(target.getClass());
//如何设置增强
hancer.setCallback(this);
//返回并创建对象
return (T) hancer.create();
}
}
复制代码
同样的,我们在测试类里加上下面的代码,测试 cglib
代理:
@Resource
private CglibProxyHandler cglibProxyHandler;
@Test
public void testCglibProxy() throws Exception {
//设置要代理的对象
cglibProxyHandler.setTarget(userService);
//得到代理对象
UserService proxy = cglibProxyHandler.getProxy();
//代理对象执行方法
proxy.add();
}
复制代码
可以看到, JDK
动态代理,代理的是实现了接口的类,而 Cglib
则没有这个要求,它是把要代理的类作为父类,然后创建一个代理类继承父类,复写并增强父类中的方法。
欢迎大家关注我的公众号,共同学习,一起进步。加油
本文使用 mdnice 排版