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
则没有这个要求,它是把要代理的类作为父类,然后创建一个代理类继承父类,复写并增强父类中的方法。
最后
欢迎大家关注我的公众号,共同学习,一起进步。加油
本文使用 tech.souyunku.com 排版