专栏首页xdecode利用Cglib实现AOP

利用Cglib实现AOP

前文讲了, 可以利用Spring, Guice等框架提供的容器实现AOP, 如果想绕过容器, 直接注入Class,

可以利用Cglib为对象加上动态代理,实现代码切入, 但是每次调用比较繁琐,

因此我们还需要给他加了一层语法糖, 使之更易用.

Advice

Spring带了一堆Advice, 我们只模拟实现环绕Advice, 以及增加了一个Clear切入的注解, 下面看具体实现.

 1 /**
 2  * 环绕Advie
 3  *
 4  * 可以加在类上, 或者方法上.
 5  * 加在类上的话, 类中所有无@Clear注解的方法都会被切入
 6  *
 7  *     @Before({CustomInterceptor.class, B.class})
 8  *     @Before(CustomInterceptor.class)
 9  */
10 @Inherited
11 @Retention(RetentionPolicy.RUNTIME)
12 @Target({ElementType.TYPE, ElementType.METHOD})
13 public @interface Before {
14     Class<? extends Interceptor>[] value();
15 }
 1 /**
 2  * 清除Advice
 3  *
 4  * 可以清除方法上的指定Interceptor, 若不指定, 则清除所有切入.
 5  *
 6  *     @Clear 清除所有
 7  *     @Clear(CustomInterceptor.class) 清除CustomInterceptor
 8  */
 9 @Inherited
10 @Retention(RetentionPolicy.RUNTIME)
11 @Target({ElementType.TYPE, ElementType.METHOD})
12 public @interface Clear {
13     Class<? extends Interceptor>[] value() default {};
14 }

语法糖

直接调用Cglib做切入, 需要setSuperClass, setCallback等等.

1   Enhancer enhancer = new Enhancer();
2   enhancer.setSuperclass(AopDemo.class);
3   enhancer.setCallback(new MethodInterceptorImpl());
4  
5   AopDemo demo = (AopDemo) enhancer.create();

我们需要对Enhancer以及Callback进行封装, 减少复杂度

  1 import java.util.concurrent.ConcurrentHashMap;
  2 
  3 /**
  4  * cglib中Enhancer的语法糖, 让注入更简单点
  5  */
  6 public class Enhancer {
  7     
  8     private static final ConcurrentHashMap<String, Object> singleton = new ConcurrentHashMap<String, Object>();
  9     
 10     private Enhancer(){}
 11 
 12     public static <T> T enhance(Class<T> targetClass) {
 13         return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback());
 14     }
 15     
 16     public static <T> T enhance(Class<T> targetClass, Interceptor... injectInters) {
 17         return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback(injectInters));
 18     }
 19 
 20     public static <T> T getTarget(String singletonKey) {
 21         return (T)singleton.get(singletonKey);
 22     }
 23     
 24     public static <T> T enhance(String singletonKey, Class<T> targetClass) {
 25         Object target = singleton.get(singletonKey);
 26         if (target == null) {
 27             target = enhance(targetClass);
 28             singleton.put(singletonKey, target);
 29         }
 30         return (T)target;
 31     }
 32     
 33     public static <T> T enhance(String singletonKey, Class<T> targetClass, Interceptor... injectInters) {
 34         Object target = singleton.get(singletonKey);
 35         if (target == null) {
 36             target = enhance(targetClass, injectInters);
 37             singleton.put(singletonKey, target);
 38         }
 39         return (T)target;
 40     }
 41     public static <T> T enhance(Object target) {
 42         return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target));
 43     }
 44     
 45     public static <T> T enhance(Object target, Interceptor... injectInters) {
 46         return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target, injectInters));
 47     }
 48     public static <T> T enhance(String singletonKey, Object target) {
 49         Object result = singleton.get(singletonKey);
 50         if (result == null) {
 51             result = enhance(target);
 52             singleton.put(singletonKey, result);
 53         }
 54         return (T)result;
 55     }
 56     
 57     public static <T> T enhance(String singletonKey, Object target, Interceptor... injectInters) {
 58         Object result = singleton.get(singletonKey);
 59         if (result == null) {
 60             result = enhance(target, injectInters);
 61             singleton.put(singletonKey, result);
 62         }
 63         return (T)result;
 64     }
 65     
 66 }
 67 
 68 
 69 import net.sf.cglib.proxy.MethodInterceptor;
 70 import net.sf.cglib.proxy.MethodProxy;
 71 
 72 import java.lang.reflect.Method;
 73 import java.util.HashSet;
 74 import java.util.Set;
 75 
 76 /**
 77  * Callback.
 78  */
 79 class Callback implements MethodInterceptor {
 80     
 81     private Object injectTarget = null;
 82     private final Interceptor[] injectInters;
 83     
 84     private static final Set<String> excludedMethodName = buildExcludedMethodName();
 85     private static final InterceptorManager interMan = InterceptorManager.me();
 86 
 87     public Callback() {
 88         this.injectInters = InterceptorManager.NULL_INTERS;
 89     }
 90     
 91     public Callback(Interceptor... injectInters) {
 92         checkInjectInterceptors(injectInters);
 93         this.injectInters = injectInters;
 94     }
 95     
 96     public Callback(Object injectTarget, Interceptor... injectInters) {
 97         if (injectTarget == null) {
 98             throw new IllegalArgumentException("injectTarget can not be null.");
 99         }
100         checkInjectInterceptors(injectInters);
101         this.injectTarget = injectTarget;
102         this.injectInters = injectInters;
103     }
104     
105     private void checkInjectInterceptors(Interceptor... injectInters) {
106         if (injectInters == null) {
107             throw new IllegalArgumentException("injectInters can not be null.");
108         }
109         for (Interceptor inter : injectInters) {
110             if (inter == null) {
111                 throw new IllegalArgumentException("interceptor in injectInters can not be null.");
112             }
113         }
114     }
115     
116     public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
117         if (excludedMethodName.contains(method.getName())) {
118             // if (method.getName().equals("finalize"))
119             //     return methodProxy.invokeSuper(target, args);
120             // return this.injectTarget != null ? methodProxy.invoke(this.injectTarget, args) : methodProxy.invokeSuper(target, args);
121             
122             // 保留上面注释部分,此处为优化
123             if (this.injectTarget == null || method.getName().equals("finalize")) {
124                 return methodProxy.invokeSuper(target, args);
125             } else {
126                 return methodProxy.invoke(this.injectTarget, args);
127             }
128         }
129         
130         if (this.injectTarget != null) {
131             target = this.injectTarget;
132             Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, target.getClass(), method);
133             Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
134             invocation.useInjectTarget = true;
135             invocation.invoke();
136             return invocation.getReturnValue();
137         }
138         else {
139             Class<?> targetClass = target.getClass();
140             if (targetClass.getName().indexOf("$$EnhancerByCGLIB") != -1) {
141                 targetClass = targetClass.getSuperclass();
142             }
143             Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, targetClass, method);
144             Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
145             invocation.useInjectTarget = false;
146             invocation.invoke();
147             return invocation.getReturnValue();
148         }
149     }
150 
151     private static final Set<String> buildExcludedMethodName() {
152         Set<String> excludedMethodName = new HashSet<String>();
153         Method[] methods = Object.class.getDeclaredMethods();
154         for (Method m : methods) {
155             excludedMethodName.add(m.getName());
156         }
157         // getClass() registerNatives() can not be enhanced
158         // excludedMethodName.remove("getClass");    
159         // excludedMethodName.remove("registerNatives");
160         return excludedMethodName;
161     }
162 }

封装后可以直接使用一句话, 还可用来增强已有对象

1         AopDemo demo = Enhancer.enhance(AopDemo.class);

示例

 1 @Before({PrivilegeInterceptor.class, LogInterceptor.class})
 2 public class AopDemo {
 3 
 4     public static void main(String[] args){
 5         AopDemo demo = Enhancer.enhance(AopDemo.class);
 6         demo.doSomething();
 7         demo.doOtherthing();
 8 
 9     }
10 
11     public void doOtherthing() {
12         // 默认沿用Class的interceptor
13         System.out.println("do 111111111111111");
14     }
15 
16     @Clear(PrivilegeInterceptor.class)
17     public void doSomething() {
18         // 手动清除了权限Interceptor
19         System.out.println("do 222222222222222");
20     }
21 }
 1 public class LogInterceptor implements Interceptor{
 2     @Override
 3     public void intercept(Invocation inv) {
 4         inv.invoke();
 5         System.out.println("Log记录入库");
 6     }
 7 }
 8 
 9 public class PrivilegeInterceptor implements Interceptor{
10     @Override
11     public void intercept(Invocation inv) {
12         System.out.println("鉴权成功");
13         inv.invoke();
14     }
15 }

doOtherthing执行结果

鉴权成功 do 111111111111111 Log记录入库

doSomething执行结果

do 222222222222222 Log记录入库

其他使用直接用来增强对象

1         AopDemo demoSinle1 = Enhancer.enhance(AopDemo.getInstance());

在enhance里new Interceptor

1         AopDemo demo3 = Enhancer.enhance(AopDemo.class, new Interceptor() {
2             @Override
3             public void intercept(Invocation inv) {
4                 System.out.println("new before");
5                 inv.invoke();
6                 System.out.println("new after");
7             }
8         });
9         demo3.doSomething();

在需要增强的方法上写@Before

1     @Before(LogInterceptor.class)
2     public void doOtherthing() {
3     }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring MVC核心技术

    目录 异常处理 类型转换器 数据验证 文件上传与下载 拦截器 ----  异常处理 Spring MVC中, 系统的DAO, Service, Controll...

    用户1216491
  • Protocol Buffer序列化对比Java序列化.

    初识 Protocol Buff是谷歌推出的一种序列化协议. 而Java序列化协议也是一种协议. 两者的目的是, 将对象序列化成字节数组, 或者说是二进制数据,...

    用户1216491
  • 初识AOP与动态代理

    AOP AOP是指在jvm运行时, 动态将代码切入到指定位置. OOP是一个维度上写代码, AOP是把他切开来, 变成立体的. 这样的好处是: 业务逻辑跟辅助逻...

    用户1216491
  • 简单音乐播放器的实现

    http://download.csdn.net/download/xinpengfei521/9627986

    IT大飞说
  • [剑指offer] 跳台阶

    一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

    尾尾部落
  • 【运营】任意两个时间段的复购率?Power BI一招帮你搞定

    在日常的运营管理中,我们经常会遇到想要查看某个时间段的用户在下一个时间段的复购情况,而且时间段是任意的,可以按月,可以按周,可以任意选择时间段,那么这个该如何用...

    陈学谦
  • 设计模式的征途—9.组合(Composite)模式

    树形结构在软件中随处可见,比如操作系统中的目录结构,公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设...

    Edison Zhou
  • Swift:属性访问类别

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    菜菜不吃蔡
  • 自治的对象才是好对象

    当我们将对象的行为看作职责时,就赋予了对象的生命与意识,使得我们能够以拟人的方式对待对象。一个聪明的对象是对象自己知道应该履行哪些职责,拒绝履行哪些职责,以及该...

    张逸
  • No enclosing instance of type Test is accessible. Must qualify the allocation with an enclosing inst

    当时没有注意,仔细想了想,也是合理的。main是Test类的static方法,按照常理它只能访问Test类中static资源,而class A是非static所...

    Frank909

扫码关注云+社区

领取腾讯云代金券