今天总结的是Spring 的AOP原理。本文不讲使用,只讲原理!这里贴笔者收藏夹里两篇很不错的关于AOP的文章:
1、springboot aop的execution 表达式详解
2、【漫画】AOP 面试造火箭事件始末
好了,Talk is cheap. Show you the code。
AOP的入口在哪
我们回忆一下,我们写切面时,要把它定义为spring的bean。基于这个切面bean,做了代理增强。透过这句话你想到了什么?如果你熟悉Spring Ioc的话,bean 意味着往ioc容器靠,对bean做处理意味着往后置处理器靠。那么你一定会想到Spring的后置处理器BeanPostProcessor,它可以在bean的初始化前后进行处理。这就是AOP的初始入口。
BeanPostProcessor是属于Ioc范畴,但是接下来分析AOP原理,必须得基于它开始。所以笔者尽量从简讲解,将篇幅尽量留给AOP。
BeanPostProcessor后置处理器的调用发生在spring ioc容器完成Bean实例对象的创建和属性的依赖注入之后。那什么时候触发Bean实例对象的创建和属性的依赖注入之后呢?有两种情况:
- 应用程序第一次向容器索取Bean时通过getBean()方法完成的。
- 当你使用@Lazy(value = false)或者不使用该注解声明Bean时 容器将会在初始化时对所配置的Bean进行预实例化
我们看一下源码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 省略部分代码
Object exposedObject = bean;
try {
// 对bean属性进行依赖注入
populateBean(beanName, mbd, instanceWrapper);
// Bean实例的依赖注入完成后,开始对Bean实例进行初始化
// 为Bean实例对象应用BeanPostProcessor后置处理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分代码
}
initializeBean方法主要就是遍历所有注册的后置处理器,回调后置处理器的before与after方法,对Bean实例初始化前后做一些处理。源码就不贴啦~
增强策略选择
我们知道了AOP的入口,那么接下来就是要知道他是具体用什么进行增强的。我们看一下后置处理器的实现类,找一下。就是这家伙AbstractAutoProxyCreator
我们思考一下,如果是你来设计,你要做增强,会选择BeanPostProcessor的postProcessBeforeInitialization还是postProcessAfterInitialization进行中增强呢?什么是增强?肯定是在目标类完整的情况下增强才有意义,所以目标锁定postProcessAfterInitialization方法。我们看一下postProcessAfterInitialization。
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
}
有一个很核心方法wrapIfNecessary,我们跟进去,着重分析一下。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 判断是否应该处理这个bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 判断是否是一些InfrastructureClass或者是否应该跳过这个bean
// 所谓InfrastructureClass就是指Advice、PointCut、Advisor等接口的实现类
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取这个bean的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
createProxy方法里最终调用的是proxyFactory.getProxy(getProxyClassLoader())
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 省略部分代码
return proxyFactory.getProxy(getProxyClassLoader());
}
我们都知道AOP的代理有两种方式:JDK以及CGLib。那么选哪一种呢?这里用的是工厂模式。
方法调用链路:getProxy->createAopProxy->getAopProxyFactory->createAopProxy
发现最后的createAopProxy走的是DefaultAopProxyFactory 的实现。里面做了JDK与CGLib的策略选择。
我们都知道当目标类是接口,则走JDK动态代理,其他的可以选择走CGLib动态代理。看到源码其实还有一种情况也是会走JDK动态代理–符合Proxy.isProxyClass(targetClass):
当且仅当使用getProxyClass方法或newProxyInstance方法动态将指定的类生成为代理类时
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
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);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
代理对象的生成
我们分别看一下JDK与CGLib两种方式的代理对象的生成方式
JDK: 用的JDK 的Proxy。底层原理是反射技术
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
}
CGLib: 用的Enhancer 。底层原理是ASM字节码增强技术
class CglibAopProxy implements AopProxy, Serializable {
public Object getProxy(@Nullable ClassLoader classLoader) {
// .....省略部分代码
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
// 省略部分代码
}
}
切面是如何织入的
在JDK动态代理,核心在InvocationHandler的invoke方法上,生成的代理对象的方法调用都会委派到invoke方法。我们着重分析一下Spring AOP是如何织入的
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 目标对象未实现eaquals()方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
// 目标对象未实现hashCode()方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 直接反射调用Advised接口或者其父接口中定义的方法,不应用通知
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获得目标对象的类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取可以运用到此方法上的拦截器列表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果没有可以运用到此方法上的拦截器,则直接反射调用Method.invoke(target, args)
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 通过拦截器列表执行joinpoint.
retVal = invocation.proceed();
}
// Massage return value if necessary.
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);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 这个AopContext内部维护了threadlocal实例.
AopContext.setCurrentProxy(oldProxy);
}
}
}
在CGLib动态代理中,核心是方法拦截器MethodInterceptor的intercept的方法上。织入就是发生在这里,思路跟jdk的基本一致。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获得目标对象的类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 如果没有可以应用到此方法上的拦截器,则直接反射调用methodProxy.invoke(target, argsToUse)
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 创建CglibMethodInvocation
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
主要思路:先获取应用到此方法上拦截器列表(Interceptor Chain)。如果有拦截器,则应用拦截器,并执行连接点(joinPoint);如果没有拦截器列表,则直接反射执行连接点。这里关键是拦截器链是如何获取的,以及它又是如何执行的。
另外,AopContext熟不熟悉?当在调用同类方法,增强失效的时候,基本就会请这家伙出山解决。
我们复习一下为何会失效?因为增强方法调用同类方法其实就是this.xxx()。this指代的是目标类而不是代理类。要想调用同类方法也起效果,思路只有一种,就是要走代理类。具体解决方法有以下两种:
- 强制拿出代理类来执行:就是AopContext这家伙
- 显示触发代理类执行:注入自身实例显示调用
给个小作业:在早版本的Dubbo中有这么一个问题,就是@Transactional与@Service(dubbo的)共用时,会导致注册中心注册的服务实例时是个代理对象!导致调用方调用异常。读者可以思考这个问题。
凡是基于AOP的设计,都会有笔者说的这个问题,像@Transactional等。使用过程中切记!其实类似的还有个synchronized,同步方法嵌套调用,同步失效。但是原理就截然不同。后面我们在并发编程专栏着重讲解,我们共同期待~
拦截器链如何获取与执行
通过上面的代码我们可以知道拦截器链是通过AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice获取的
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable 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;
}
可以看到,获取拦截器其实是由AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()方法完成的,且获取到的结果会被缓存起来。接下来我们分析这个方法实现。
主要思路:从提供的配置实例config中获取Advisor列表,遍历处理这些Advisor。如果是IntroductionAdvisor,则判断此Advisor能否运用到目标类targetClass上。如果是PointcutAdvisor,则判断此Advisor能否运用到目标方法Method上。将满足条件的Advisor通过AdvisorAdaptor转化成拦截器列表返回
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 这里实际上注册了一些列AdvisorAdaptor,用于将Advisor转换成MethodInterceptor
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 获得Advisor列表
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 检查当前Advisor的切入点是否可以匹配当前方法
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
// 如果匹配将Advisor转换成MethodInterceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
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;
}
}
这个方法执行完成后,Advised中配置的能够运用到连接点(JointPoint)或者目标对象(TargetObject)的Advisor全部转化成MethodInterceptor。接下来看看拦截器链是怎么起作用
JDK:
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
CGLib:
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}else {
// CglibMethodInvocation继承ReflectiveMethodInvocation
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
从源码里可以看出,如果得到拦截器链为空,jdk的处理方式是直接反射调用目标方法,cglib是用methodProxy.invoke,复杂点,否则创建MethodInvocation,调用其proceed()方法,触发拦截器链的执行
public Object proceed() throws Throwable {
// 如果拦截器执行完了,则执行连接点.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
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;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 动态匹配:运行时参数是否满足匹配条件
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 动态匹配失败,略过当前拦截器,递归调用下一个拦截器
return proceed();
}
}
else {
// 执行当前拦截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
在CGLib中有这么一个细的知识点:MethodProxy#invokeSuper和invoke的区别、cglib动态代理拦截器中使用MethodProxy#invokeSuper和invoke的区别
至此,拦截器链就完美地形成了。
触发通知大揭秘
我们通过前文分析已经知道AOP的增强具体体现在拦截器链上,拦截器链一个很核心就是AdvisorAdaptor适配器将Advisor转化成连接器列表。这个适配器到底有什么魔力呢?我们探一下究竟
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
// 省略部分代码
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 省略部分代码
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
// 省略部分代码
}
GlobalAdvisorAdapterRegistry 类负责拦截器的适配和注册过程。起到了适配器和单例模式的作用
public final class GlobalAdvisorAdapterRegistry {
private GlobalAdvisorAdapterRegistry() {
}
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
public static AdvisorAdapterRegistry getInstance() {
return instance;
}
static void reset() {
instance = new DefaultAdvisorAdapterRegistry();
}
}
DefaultAdvisorAdapterRegistry类用来完成各种通知的适配和注册过程。类中设置了一系列适配器,正是这些适配器的实现,为Spring AOP提供了织入能力。
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
// 一系列熟知的适配器
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(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[0]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
我们以MethodBeforeAdviceAdapter为例子看一下具体实现
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
Spring AOP为了实现Advice的织入,设计了特定的拦截器对这些功能进行封装。我们看看MethodBeforeAdviceInterceptor类是如何完成封装的。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
可以看到invoke()方法中首先触发了Advice的before方法回调,然后才执行proceed()方法。其他的MethodInterceptor(spring的)就不再一一赘述了,读者们可以源码看一下,比较简单。
至此,我们知道了对目标对象的增强是通过拦截器实现的。
本文就到此结束了,我们下文见,谢谢
github: honey开源系列组件作者