前文讲了, 可以利用Spring, Guice等框架提供的容器实现AOP, 如果想绕过容器, 直接注入Class,
可以利用Cglib为对象加上动态代理,实现代码切入, 但是每次调用比较繁琐,
因此我们还需要给他加了一层语法糖, 使之更易用.
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 }