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