动手写web框架(8): AOP实现

定义切面注解

Aspect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.smart4j.framework.annotation;
import java.lang.annotation.*;
/**
* 切面注解
* Created by Roger on 2016/11/24.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
/**
* 注解
*/
Class<? extends Annotation> value();
}

代理框架

Proxy接口

代理接口Proxy,定义了一个doProxy方法,传入一个ProxyChain,用于执行“链式代理”。

所谓链式代理就是,将多个代理串起来,一个个去执行,执行顺序取决于添加到链上的先后顺序。

同一个目标对象,可能会被多个切面代理,因而采用代理链的方式。

Proxy
1
2
3
4
5
6
7
8
9
10
11
12
13
package org.smart4j.framework.proxy;
/**
* 代理
* Created by Roger on 2016/11/24.
*/
public interface Proxy {
/**
* 执行链式代理
*/
Object doProxy(ProxyChain proxyChain) throws Throwable;
}

ProxyChain

ProxyChain类中定义了一系列的成员变量,包括 targetClass(目标类)、targetObject(目标对象)、targetMethod(目标方法)、methodProxy(方法代理类)、methodParams(方法参数)、proxyList(代理列表)、proxyIndex(代理索引)。

methodProxy是 CGLib 提供的一个方法代理对象。

proxyIndex充当代理对象的计数器,若未达到proxyList的上限,则从proxyList中取出Proxy对象,并调用其doProxy()方法,在Proxy接口的实现中会提供相应的横切逻辑,并调用doProxyChain()方法,随后将再次调用当前ProxyChain对象的doProxyChain()方法,直到proxyIndex达到proxyList的上限为止,最后调用methodProxyinvokeSuper()方法,执行目标对象的业务逻辑。

ProxyChain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package org.smart4j.framework.proxy;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 代理链
* 链式代理:可将多个代理串成一条链,然后一个个执行
* Created by Roger on 2016/11/24.
*/
public class ProxyChain {
/**
* 目标类
*/
private final Class<?> targetClass;
/**
* 目标对象
*/
private final Object targetObject;
/**
* 目标方法
*/
private final Method targetMethod;
/**
* 方法代理
*/
private final MethodProxy methodProxy;
/**
* 方法参数
*/
private final Object[] methodParams;
/**
* 代理列表
*/
private List<Proxy> proxyList = new ArrayList<>();
/**
* 代理索引
*/
private int proxyIndex = 0;
public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
this.targetClass = targetClass;
this.targetObject = targetObject;
this.targetMethod = targetMethod;
this.methodProxy = methodProxy;
this.methodParams = methodParams;
this.proxyList = proxyList;
}
public Class<?> getTargetClass() {
return targetClass;
}
public Method getTargetMethod() {
return targetMethod;
}
public Object[] getMethodParams() {
return methodParams;
}
public Object doProxyChain() throws Throwable {
Object methodResult;
if (proxyIndex < proxyList.size()){
methodResult = proxyList.get(proxyIndex++).doProxy(this);
}else {
methodResult = methodProxy.invokeSuper(targetObject, methodParams);
}
return methodResult;
}
}

ProxyManager

ProxyManager的作用是:提供一个创建代理对象的方法,输入一个目标类和一组Proxy接口实现,输出一个代理对象。

借助CGLib提供的MethodInterceptorEnhancer完成代理对象的创建。

ProxyManager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package org.smart4j.framework.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.List;
/**
* 代理管理器
* Created by Roger on 2016/11/24.
*/
public class ProxyManager {
@SuppressWarnings("unchecked")
public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList){
return (T) Enhancer.create(targetClass, new MethodInterceptor() {
@Override
public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();
}
});
}
}

AbstractProxy

抽象类AbstractProxy实现了接口Proxy,并提供了一系列的钩子方法,这些方法可以在其子类中选择性地实现。

AbstractProxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package org.smart4j.framework.proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
/**
* 切面抽象类
* 提供一些"钩子方法", 这些方法可以在子类中有选择性的实现
* Created by Roger on 2016/11/24.
*/
public abstract class AspectProxy implements Proxy{
private static final Logger LOGGER = LoggerFactory.getLogger(AspectProxy.class);
@Override
public final Object doProxy(ProxyChain proxyChain) throws Throwable {
Object result = null;
Class<?> cls = proxyChain.getTargetClass();
Method method = proxyChain.getTargetMethod();
Object[] params = proxyChain.getMethodParams();
begin();
try {
if (intercept(cls, method, params)){
before(cls, method, params);
result = proxyChain.doProxyChain();
after(cls, method, params, result);
}else {
result = proxyChain.doProxyChain();
}
} catch (Exception e) {
LOGGER.error("proxy failure", e);
error(cls, method, params, e);
throw e;
} finally {
end();
}
return result;
}
public void begin(){
}
public boolean intercept(Class<?> cls, Method method, Object[] params){
return true;
}
/**
* 前置增强
* @param cls
* @param method
* @param params
*/
public void before(Class<?> cls, Method method, Object[] params){
}
/**
* 后置增强
* @param cls
* @param method
* @param params
* @param result
*/
public void after(Class<?> cls, Method method, Object[] params, Object result){
}
/**
* 抛出增强
* @param cls
* @param method
* @param params
* @param throwable
*/
public void error(Class<?> cls, Method method, Object[] params, Throwable throwable){
}
public void end(){
}
}

加载AOP框架

通过AopHelper获取所有的目标类及其被拦截的切面类实例,并通过ProxyManager创建目标类的代理对象,最后放入Bean Map中。

AopHelper要在IocHelper之前加载,因为首先要通过AopHelper获取代理对象,然后才能通过IocHepler进行依赖注入。

AopHelper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package org.smart4j.framework.helper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smart4j.framework.annotation.Aspect;
import org.smart4j.framework.proxy.AspectProxy;
import org.smart4j.framework.proxy.Proxy;
import org.smart4j.framework.proxy.ProxyManager;
import org.smart4j.framework.proxy.TransactionProxy;
import java.lang.annotation.Annotation;
import java.util.*;
/**
* 方法拦截助手类
* Created by Roger on 2016/11/24.
*/
public final class AopHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);
static {
try {
Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
for (Map.Entry<Class<?>, List<Proxy>> entry : targetMap.entrySet()) {
Class<?> targetClass = entry.getKey();
List<Proxy> proxyList = entry.getValue();
Object proxy = ProxyManager.createProxy(targetClass, proxyList);
BeanHelper.setBean(targetClass, proxy);
}
} catch (Exception e) {
LOGGER.error("aop failure", e);
}
}
private static Set<Class<?>> createTargetClassSet(Aspect aspect) {
Set<Class<?>> targetClassSet = new HashSet<>();
Class<? extends Annotation> annotation = aspect.value();
if (annotation != null && !annotation.equals(Aspect.class)) {
targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
}
return targetClassSet;
}
/**
* 获取"切面类"和"目标类集合"之间的对应关系
*
* @return
*/
public static Map<Class<?>, Set<Class<?>>> createProxyMap() {
Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>();
addAspectProxy(proxyMap);
addTransactionProxy(proxyMap);
return proxyMap;
}
/**
* 切面类必须满足两个条件: 1.扩展AspectProxy抽象类; 2.还需要带有Aspect注解
*
* @param proxyMap
*/
private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> proxyMap) {
// 获取所有切面代理, 扩展AspectProxy抽象类
Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
for (Class<?> proxyClass : proxyClassSet) {
// 判断是否带有Aspect注解
if (proxyClass.isAnnotationPresent(Aspect.class)) {
Aspect aspect = proxyClass.getAnnotation(Aspect.class);
// 获取目标类集合
Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
proxyMap.put(proxyClass, targetClassSet);
}
}
}
private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap) {
Set<Class<?>> serviceClassSet = ClassHelper.getServiceClassSet();
proxyMap.put(TransactionProxy.class, serviceClassSet);
}
/**
* 获取"目标类"与"切面类实例"之间的映射关系
* 一个目标类可能对应多个切面
* @param proxyMap
* @return
*/
public static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
for (Map.Entry<Class<?>, Set<Class<?>>> entry : proxyMap.entrySet()) {
Class<?> proxyClass = entry.getKey();
Set<Class<?>> targetClassSet = entry.getValue();
for (Class<?> targetClass : targetClassSet) {
// 反射得到切面类实例
Proxy proxy = (Proxy) proxyClass.newInstance();
if (targetMap.containsKey(targetClass)) {
targetMap.get(targetClass).add(proxy);
} else {
List<Proxy> proxyList = new ArrayList<>();
proxyList.add(proxy);
targetMap.put(targetClass, proxyList);
}
}
}
return targetMap;
}
}