引:前一节讲到Spring的核心概念IOC,那么就不能不提到Spring的另一个核心概念AOP,我们先是先讲一下它的概念与原理实现,然后在讲Spring中AOP的实现。
AOP
AOP思想
AOP(Aspect Oriented Programming的缩写,意为:面向切面编程)是对OOP的一种补充。
- 面向对象(OOP)引入了继承、多态、封装,将系统的业务功能按照模块划分,每个模块用一个或多个类来表示。而对于一些系统功能,无法使用OOP的思想来实现它们。这些系统功能往往穿插在业务功能的各处,和业务代码耦合在一起;而且系统功能往往会被重复使用,这就导致了模块不利于复用,这就是使用OOP实现系统功能的弊端。
- AOP即为面向切面编程,它把系统需求按照功能分门归类,把它们封装在一个个切面中,然后再指定这些系统功能往业务功能,主要应用于权限认证、日志,事务等。
它的主要是好处如下:
降低模块之间的耦合度
使系统容易扩展
更好的代码复用。
AOP实现原理
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。而Spring采用的是动态代理技术,关于动态代理的实现可以参照自己之前的博客 设计模式之禅——代理模式一文中的动态代理这一节去了解。
SpringAOP实现
Spring的AOP实现遵守AOP联盟的约定。同时Spring又扩展了它,增加了Pointcut、Advisor等一些接口使得其更加灵活。
Spring AOP的基本概念
- 切面(Aspect):类似于OOP中的Class,一个Aspect存放一个系统功能的所有逻辑。切面用Spring的 Advisor或拦截器实现。
- 连接点(Joinpoint):程序执行过程中的某一事件,如方法被调用时、抛出异常时。
- 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上。
- 引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口。
- 目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象(POJO)。
- AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- 织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
- 通知(Advice):具体的横切逻辑;Spring中有五种Advice:
- 前置通知(Before Advice)
- 后置通知(After Advice)
- 返回通知(After Return Advice)
- 环绕通知(Around Advice)
- 抛出异常后通知(After Throwing Advice)
SpringAOP动态代理
Spring AOP中使用了两种动态代理,一种是JDK的动态代理,一种CGLIB的动态代理。JDK的动态代理必须指定接口,这些接口都是已经被代理对象实现了的;而CGLIB代理则不需要指定接口。
JDK动态代理
如果被代理对象实现了需要被代理的接口,则使用JDK的动态代理。我们一步步来看这个过程:
首先明确我们使要生成一个代理,而Spring的内部机制是由FactoryBean的getObject方法来产生的,所以我们会一步步debug到这个方法行(在FactoryBeanRegistrySupport类的doGetObjectFromFactoryBean中),我们看看这个方法的源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public Object getObject() throws BeansException {
// 初始化通知器链,为代理对象配置通知器链。
this.initializeAdvisorChain();
//区分SingleTon和ProtoType,生成对应的Proxy
if(this.isSingleton()) {
// 只有SingleTon的Bean才会一开始就初始化,ProtoType的只有在请求的时候才会初始化,代理也一样
return this.getSingletonInstance();
} else {
if(this.targetName == null) {
this.logger.warn("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property.");
}
return this.newPrototypeInstance();
}
}到达getObject方法后,我们需要去看看它是怎么初始化通知链的就是initializeAdvisorChain的代码:
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
43private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
// 初始化过程的标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。
if(!this.advisorChainInitialized) {
if(!ObjectUtils.isEmpty(this.interceptorNames)) {
if(this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) - cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
if(this.interceptorNames[this.interceptorNames.length - 1].endsWith("*") && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
String[] var1 = this.interceptorNames;
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
String name = var1[var3];
if(this.logger.isTraceEnabled()) {
this.logger.trace("Configuring advisor or advice '" + name + "'");
}
if(name.endsWith("*")) {
if(!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");
}
this.addGlobalAdvisor((ListableBeanFactory)this.beanFactory, name.substring(0, name.length() - "*".length()));
} else {
Object advice;
if(!this.singleton && !this.beanFactory.isSingleton(name)) {
advice = new ProxyFactoryBean.PrototypePlaceholderAdvisor(name);
} else {
advice = this.beanFactory.getBean(name);
}
this.addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
}初始化只是在应用第一次通过ProxyFactoryBean获取代理对象的时候。完成这个初始化之后,接着会读取配置中出现的所有通知器(把通知器的名字交给容器的getBean,IOC容器的回调获取通知器),把通知器加入拦截器链(addAdvisoronChainCreation实现)。
生成代理对象,利用ProxyFactoryBean的getSingletonInstance方法,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private synchronized Object getSingletonInstance() {
if(this.singletonInstance == null) {
//这里会调用getBean,获取被代理对象
this.targetSource = this.freshTargetSource();
if(this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
// 根据 AOP 框架判断需要代理的接口
Class<?> targetClass = this.getTargetClass();
if(targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//这里是设置代理对象的接口
this.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
super.setFrozen(this.freezeProxy);
//这里方法会使用ProxyFactory生成需要的Proxy
this.singletonInstance = this.getProxy(this.createAopProxy());
}
return this.singletonInstance;
}进入ProxyCreatorSupport的createAopProxy,源码如下:
1
2
3
4
5
6
7protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//通过AopProxyFactory取得AopProxy,AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}那么DefaultAopProxyFactory如何生成AopProxy了,这里有两种方式,JdkDynamicAopProxy和CglibProxyFactory,DefaultAopProxyFactory的createAopProxy的源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
//获取配置的目标对象
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
//如果没有目标对象,抛出异常,提醒AOP应用提供正确的目标配置
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 这个判断很重要,通过目标类是否是接口来决定采用什么代理方式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//由于CGLIB是一个第三方类库,所以需要在CLASSPATH中配置
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
}由于我们这里目标类是接口,所以采用JdkDynamicAopProxy 生成AopProxy代理对象,我们可以看一下JdkDynamicAopProxy的invoke方法源码:
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
74public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
Object var13;
try {
if(!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
Boolean var20 = Boolean.valueOf(this.equals(args[0]));
return var20;
}
if(!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
Integer var18 = Integer.valueOf(this.hashCode());
return var18;
}
if(method.getDeclaringClass() == DecoratingProxy.class) {
Class var17 = AopProxyUtils.ultimateTargetClass(this.advised);
return var17;
}
Object retVal;
// Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
if(!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
return retVal;
}
if(this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//获得目标对象的类
target = targetSource.getTarget();
if(target != null) {
targetClass = target.getClass();
}
// 获得拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
if(chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
//创建MethodInvocation
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 处理通知
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if(retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
} else if(retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
}
var13 = retVal;
} finally {
if(target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if(setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
return var13;
}
CGLIB动态代理
如果被代理对象没有实现需要被代理的接口,则使用CGLIB动态代理,CGLIB动态代理按照前面的分析基本与JDK动态代理一样,由于在Spring AOP中对应的包装类为CglibAopProxy,CglibAopProxy的intercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常类似的,只是在CglibAopProxy中构造的是CglibMethodInvocation对象来完成拦截器链的调用,这里看一下与invoke类似的getCallbacks源码: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
38private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
Object targetInterceptor;
if(exposeProxy) {
targetInterceptor = isStatic?new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()):new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
} else {
targetInterceptor = isStatic?new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()):new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
Callback targetDispatcher = (Callback)(isStatic?new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()):new CglibAopProxy.SerializableNoOp());
Callback[] mainCallbacks = new Callback[]{aopInterceptor, (Callback)targetInterceptor, new CglibAopProxy.SerializableNoOp(), targetDispatcher, this.advisedDispatcher, new CglibAopProxy.EqualsInterceptor(this.advised), new CglibAopProxy.HashCodeInterceptor(this.advised)};
Callback[] callbacks;
if(isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap(methods.length);
for(int x = 0; x < methods.length; ++x) {
// 获得拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
// 准备处理通知
fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), Integer.valueOf(x));
}
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
} else {
callbacks = mainCallbacks;
}
return callbacks;
}