Java中的动态代理
说起动态代理,首先想到的就是Spring,在Spring中有两种动态代理方式:JDK动态代理和Cglib动态代理。
JDK动态代理
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();
}
}
执行结果:

Cglib动态代理
我们也要实现一个接口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 排版