cglib动态代理

叁歲伎倆 2022-04-24 00:14 393阅读 0赞

1.示例需要代码

1.接口代码
  1. public interface People {
  2. public String workAndGetReward();
  3. public String reward();
  4. }
2.接口实现类代码
  1. public class Programmer implements People {
  2. @Override
  3. public String workAndGetReward() {
  4. System.out.println("Programmer works hard under 996.");
  5. return reward();
  6. }
  7. @Override
  8. public String reward() {
  9. return "Then he goes icu.";
  10. }
  11. }
3.动态代理处理类代码
  1. import java.lang.reflect.Method;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import net.sf.cglib.proxy.Enhancer;
  5. import net.sf.cglib.proxy.MethodInterceptor;
  6. import net.sf.cglib.proxy.MethodProxy;
  7. public class CglibProxy implements MethodInterceptor {
  8. private static Logger logger = LoggerFactory.getLogger(Programmer.class);
  9. @Override
  10. public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
  11. logger.info("before invoke:" + method.getName() + " - " + System.currentTimeMillis());
  12. Object retObj = methodProxy.invokeSuper(proxy, params);
  13. logger.info("after invoke:" + method.getName() + " - " + System.currentTimeMillis());
  14. return retObj;
  15. }
  16. // 返回目标对象的代理对象
  17. public Object newProxy(Object target) {
  18. Enhancer enhancer = new Enhancer();
  19. enhancer.setSuperclass(target.getClass());
  20. enhancer.setCallback(this);
  21. enhancer.setClassLoader(target.getClass().getClassLoader());
  22. return enhancer.create();
  23. }
  24. }
4.main代码
  1. public class App {
  2. public static void main(String[] args) {
  3. // 要代理的真实对象
  4. Programmer programmer = new Programmer();
  5. // 生成MethodInterceptor对象
  6. CglibProxy proxy = new CglibProxy();
  7. // 根据真实对象生成代理对象
  8. Programmer proxyProgrammer = (Programmer) proxy.newProxy(programmer);
  9. System.out.println(proxyProgrammer.workAndGetReward() + " - " + System.currentTimeMillis());
  10. }
  11. }

2.代码分析

cglib动态代理的核心是
Enhancer对象
我们可以通过以下步骤实现动态代理

  1. 创建Enhancer实例
  2. 通过setSuperclass方法来设置目标类
  3. 通过setCallback 方法来设置拦截对象
  4. create方法生成Target的代理类,并返回代理类的相应代理对象实例

通过这个方法和三个参数我们得到传入类型的代理对象,然后在调用方法时,会经过我们自定义的代理方法增强了,如以下输出:

  1. [main] INFO 反射.cglib动态代理.v1.Programmer - before invoke:workAndGetReward - 1554827985920
  2. [main] INFO 反射.cglib动态代理.v1.Programmer - before invoke:reward - 1554827985929
  3. [main] INFO 反射.cglib动态代理.v1.Programmer - after invoke:reward - 1554827985929
  4. [main] INFO 反射.cglib动态代理.v1.Programmer - after invoke:workAndGetReward - 1554827985929
  5. Programmer works hard under 996.
  6. Then he goes icu. - 1554827985929

从控制台的输出可以看出来workAndGetReward()方法受到了动态代理的增强
在workAndGetReward()里调用的reward()方法也受到增强

3.代码修改一

cglib也可以不用实现接口来进行动态代理
修改后的真实对象类代码:

  1. public class Programmer {
  2. public String workAndGetReward() {
  3. System.out.println("Programmer works hard under 996.");
  4. return reward();
  5. }
  6. public String reward() {
  7. return "Then he goes icu.";
  8. }
  9. }

输出:

  1. [main] INFO 反射.cglib动态代理.v1.Programmer - before invoke:workAndGetReward - 1554828540025
  2. [main] INFO 反射.cglib动态代理.v1.Programmer - before invoke:reward - 1554828540034
  3. Programmer works hard under 996.
  4. [main] INFO 反射.cglib动态代理.v1.Programmer - after invoke:reward - 1554828540034
  5. [main] INFO 反射.cglib动态代理.v1.Programmer - after invoke:workAndGetReward - 1554828540034
  6. Then he goes icu. - 1554828540034

可以看到输出顺序略有不同,猜测还会产生其他影响

4.代码修改二

如果我们把内部调用的方法改为final(private方法也会被隐形标记为final)
修改后的真实对象类代码:

  1. public class Programmer {
  2. public String workAndGetReward() {
  3. System.out.println("Programmer works hard under 996.");
  4. return reward();
  5. }
  6. private String reward() {
  7. return "Then he goes icu.";
  8. }
  9. }

输出:

  1. [main] INFO 反射.cglib动态代理.v1.Programmer - before invoke:workAndGetReward - 1554828701583
  2. [main] INFO 反射.cglib动态代理.v1.Programmer - after invoke:workAndGetReward - 1554828701592
  3. Programmer works hard under 996.
  4. Then he goes icu. - 1554828701592

可以看出此时内部调用的reward()方法不会被代理类增强了

cglib是通过生成被代理类的子类覆写被代理类里的所有非final的方法实现方法增强,与方法是内部调用还是外部调用无关,只与方法有没有被final修饰有关(private方法会被隐形修饰为final)

发表评论

表情:
评论列表 (有 0 条评论,393人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Cglib动态代理

           JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字

    相关 CGLIB动态代理

    一 说明 使用火车站卖票,使用CGLIB代理实现。 如果没有定义SellTickets接口,只定义了TrainStation(火车站类)。很显然JDK代理是无法使用了