利用Cglib实现AOP

时间:2022-04-24
本文章向大家介绍利用Cglib实现AOP,主要内容包括Advice、语法糖、示例、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

前文讲了, 可以利用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     }