转载

Java中的动态代理

Java中的动态代理

说起动态代理,首先想到的就是 Spring ,在 Spring 中有两种动态代理方式: JDK 动态代理和 Cglib 动态代理。

JDK动态代理

JDK 动态代理是 Java 本来就有的一种代理方式,关键类是 java.lang.reflect.InvocationHandler

我们先创建一个简单的 SpringBoot 项目,然后创建 UserServiceUserServiceImpl

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();
    }
}
复制代码

执行结果:

Java中的动态代理

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();
}
复制代码

执行结果:

Java中的动态代理

总结:

Java中的动态代理

可以看到, JDK 动态代理,代理的是实现了接口的类,而 Cglib 则没有这个要求,它是把要代理的类作为父类,然后创建一个代理类继承父类,复写并增强父类中的方法。

最后

欢迎大家关注我的公众号,共同学习,一起进步。加油

Java中的动态代理

本文使用 mdnice 排版

原文  https://juejin.im/post/5f1bfe2c6fb9a07e802060f2
正文到此结束
Loading...