AOP与Ioc是Spring的两大核心设计要素, 并且两者相辅相成, 共同构建起Spring的整个生态系统。
AOP 概述
AOP是Aspect-Oriented Programming (面向切面编程) 的简称, Aspect 是一种新的模块化机制, 它与面向对象(OOP)相补, OOP描述了对象自身的属性与行为, 再结合对象继承就能从纵向建立对象间的相互依赖与行为调用, 而AOP则从横向解决分散在不同业务对象中相同逻辑处理, 以获得业务过程中各部分间的低耦合性的隔离效果;
AOP概念介绍
Advice通知
Advice定义切点内容, 为切面增强提供织入接口。在Spring AOP中, 它主要描述围绕被切入方法调用而注入的切面行为。Advice是AOP中定义的一个接口(org.aopalliance.aop.Advice), 并且Spring为 AOP 切面增强 的织入做了更多的细化和扩展, 比如提供了更具体的通知类型, 如BeforeAdvice, AfterAdvice, ThrowAdvice等.
Pointcut切点
Pointcut决定Advice通知应该作用于哪个连接点, 也就是说通过Pointcut来定义需要增强的方法的集合, 这些集合的选取可以按照一定的规则来定义; 例如可以通过正则表达式进行标识, 或根据某类方法名进行匹配等.而在Pointcut的接口定义中可以看到, MethodMatcher对象可以通过正则表达式来匹配, NameMatchMethodPointcut可以通过比较方法名进行Advice的匹配;
Advisor通知器
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)之后, 需要一个把二者结合到一起代理对象, 担当此角色的就是Advisor(通知器).
AOP 的设计
在jdk1.3版本里实现了动态代理模式, 加之立于Ioc容器的基石之上, Spring AOP的实现技术核心便是动态代理, 鉴于jdk原生的代理对象Proxy是使用反射的invoke方法实现的代理, 其性能比较差同时资源消耗也大, 因此可以采用三方类生成器CGLib来实现动态代理类的字节码生成;
AOP 的实现
建立AOPProxy代理对象
在Spring AOP模块中实现代理对象生成功能, 是由在生成与装配bean对象时调用ProxyFactoryBean来完成的;
接口设计继承图
相关接口与类的解释说明
(1). ProxyConfig: 为子类提供配置属性;
(2). Advised: 通知器的相关增删配置操作;
(3). AdvisedSupport: 辅助通知器配置类;
(4). ProxyCreatorSupport: 创建代理对象的辅助类;
(5). FactoryBean: 代理对象同样使用工厂方式管理
(6). AbstractSingletonProxyFactoryBean: 工厂方式管理单例代理对象;
(7). ProxyFactory: 在Spring里面编程式使用AOP功能
(8). AspectJProxyFactory: 结合Spring与AspectJ, 使用AspectJ的AOP功能;
(9). ProxyFactoryBean: 在Spring里, 通过在Ioc容器里进行声明式的配置实现AOP功能;
(10). TransactionProxyFactoryBean: Spring的事务就是通过AOP来实现的咯;
Spring AOP 拦截调用器的实现
设计原理
在Spring AOP通过JDK的Proxy方式或CGLib方式生成代理对象的时候, 相关的拦截器已经配置到代理对象中去了, 拦截器在代理对象中起作用是通过对这些方法的回调来完成的;
JdkDynamicAopProxy的invoke拦截
如下所示生成代理对象
Proxy.newProxyInstance(classLoader, A.getClass().getInterfaces(), B);
A: 需要被代理的类对象
B: 实现的InvocationHandler接口实例对象
在InvocationHandler里面的invoke方法是对JDK Proxy代理对象进行拦截时的回调入口,里面有获取目标对象, 拦截器链等, 在这个invoke方法中, 包含了完整的拦截器链对目标对象的拦截过程, 一步步完成拦截器的增强过程, 直至最后执行到目标对象方法的执行;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
.....
Object retVal;
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取指定方法对应的拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 执行拦截器与目标方法
.....
// 处理返回结果
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
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);
}
return retVal;
}
finally {
//收尾工作
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
CGLib2AopProxy的intercept拦截
使用CglibAopProxy中的内部类DynamicAdvisedInterceptor作为通用回调处理类, 其中的intercept方法在执行时会构造CglibMethodInvocation对象来完成执行拦截器链的功能;
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
// 拦截器链为空, 直接执行目标对象方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 执行拦截器链
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 处理目标对象方法返回结果
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
对目标方法进行调用
如果没有设置拦截器, 会对目标方法直接进行调用, 通过AopUtils使用发射机制在invokeJoinpointUsingReflection方法中实现;而对于CGLibAopProxy的代理对象, 它是通过目标对象调用CGLib的MethodProxy对象来直接完成的, 拦截功能已经是封装好的, 调用形式相对简单;
AOP拦截器链的调用
无论是上面JdkDynamicAopProxy的invoke, 还是CglibAopProxy中DynamicAdvisedInterceptor的intercept方法, 他们对AOP拦截器的处理都是大同小异的. 两者对拦截器的调用都是通过在ReflectiveMethodInvocation中通过proceed方法实现的. 在proceed方法中, 会逐个运行拦截器的拦截方法, 在执行单个拦截器前会进行matches方法调用进行匹配判断, 匹配才会执行拦截器, 不匹配继续递归执行proceed方法, 最终执行完所有拦截器并调用目标对象的实现方法进行返回.
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引为-1的拦截器开始调用, 逐个递增, 如果拦截器调用玩了, 则执行目标对象方法;
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 这里沿着定义好的interceptorOrInterceptionAdvice链进行处理
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 判断是拦截器链对象
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 拦截器的动态匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 递归调用
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 单单的一个Interceptor对象, 直接调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
配置通知器
下面逆序查看
(1). 执行时获取拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
(2). 使用AdvisedSupport进行获取
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
(3). 缓存中没有从默认的DefaultAdvisorChainFactory中加载
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 到这里 Advised中的advisors是已经配置进去了的, 直接使用
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
// 切入点类型的通知器
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
// 判断这个方法匹配对象是否为动态的, 是的话需要在拦截器运行时判断执行
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 执行多个AOP功能的高级接口
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 其他的类型通知器
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
(4). 在ProxyFactoryBean的getObject方法中对advisor进行初始化, 从XML配置中获取了advisor通知器;
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
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));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
// 全局通知器
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
// 判断是通知器对象时单例还是属性(多例)类型
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
// 添加通知器到全局通知器链中
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
Advice通知的实现
上面说了DefaultAdvisorChainFactory中的getInterceptorsAndDynamicInterceptionAdvice是获取Advisor chain的地方, 同时这里也隐藏着AOP实现的重要细节, 我们看GlobalAdvisorAdapterRegistry, 它本身只是一个简单的单例模式的应用, 而各种通知的适配和注册工作都是由它里面的DefaultAdvisorAdapterRegistry完成;
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
* 默认加入三个适配器,为Spring AOP 提供编织能力
*/
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
@Override
// 把通知器转换为方法拦截器
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
这里举例分析下AfterReturningAdviceAdapter (在目标对象方法return后执行的拦截调用)
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
// 创建对应的方法拦截
return new AfterReturningAdviceInterceptor(advice);
}
}
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
//真正执行目标对象方法与AOP的Advice拦截执行的地方
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
Spring AOP 的高级特性
- HotSwappableTargetSource: 在运行时可以切换需要配置AOP功能的对象, 进行动态配置;
总结
在Spring的生态系统中, 通过对AOP的使用, 极大丰富了Spring框架的功能, 比如在各种驱动组件的实现上, 数据库事务, 日志系统埋点嵌入等都灵活运用了AOP的功能特性;
PS: 其他AOP功能操作示例