目录
- 一个例子
- 从@EnableAspectJAutoProxy注解入手
- 什么时候会创建代理对象?
- 方法执行时怎么实现拦截的?
- 总结
- 问题
- 参考
一个例子
// 定义一个切面package cn.eagle.li.source.aspect;@Component@Aspectpublic class ServiceAspect {@Pointcut(\"execution(* cn.eagle.li.source.service.*.*(..))\")public void pointCut() {}@Before(\"pointCut()\")public void methodBefore() {System.out.println(\"===== Before =====\");}@After(\"pointCut()\")public void methodAfter() {System.out.println(\"===== After =====\");}@AfterReturning(\"pointCut()\")public void methodReturn() {System.out.println(\"===== AfterReturning =====\");}@Around(\"pointCut()\")public void doAround(ProceedingJoinPoint pjp) throws Throwable {System.out.println(\"===== Around before =====\");pjp.proceed();System.out.println(\"===== Around after =====\");}}
// 一个接口package cn.eagle.li.source.service;public interface IService {void doService();}// 一个实现类package cn.eagle.li.source.service.impl;@Servicepublic class ServiceImpl implements IService {@Overridepublic void doService() {System.out.println(\"do service\");}}
// Main类@Configuration@ComponentScan(basePackages = {\"cn.eagle.li.source\"})@EnableAspectJAutoProxy(exposeProxy = true)public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);IService service = context.getBean(IService.class);service.doService();}}
执行结果如下:
===== Around before ========== Before =====do service===== AfterReturning ========== After ========== Around after =====
从@EnableAspectJAutoProxy注解入手
下面是EnableAspectJAutoProxy注解类内容
@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {//代理的实现方式,true为CGLIB, false为JDK,默认falseboolean proxyTargetClass() default false;// 要不要暴露代理对象boolean exposeProxy() default false;}
除了上面两个参数比较重要外,它还有一个Impoad8rt注解,在Spring中,只要一种注解组合了另一种注解,它就具有该注解的功能,也就是这个注解拥有了@Import注解的功能。
@Import(AspectJAutoProxyRegistrar.class)
我们看到它import了AspectJAutoProxyRegistrar这个类,我们下面再看看这个类的内容,发现它主要的工作就是注册一个name为:
org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator的BeanDefinition。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);// ......}}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
public abstract class AopConfigUtils {@Nullablepublic static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}}
public abstract class AopConfigUtils {public static final String AUTO_PROXY_CREATOR_BEAN_NAME =\"org.springframework.aop.config.internalAutoProxyCreator\";@Nullableprivate static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, \"BeanDefinitionRegistry must not be null\");if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;}RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add(\"order\", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 注册 BeanDefinition// AUTO_PROXY_CREATOR_BEAN_NAME = org.springframework.aop.config.internalAutoProxyCreator// beanDefinition = AnnotationAwareAspectJAu15a8toProxyCreator.classregistry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}}
此时有一个疑问:那就是什么时候调用这个方法来加载AnnotationAwareAspectJAutoProxyCreator这个类的BeanDefinition呢?
从下面这张图可以看到是在容器进行刷新的时候,调用invokeBeanFactoryPostProcessors这个方法来进行执行的,具体的执行过程就不展开了。
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start(\"spring.context.refresh\");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start(\"spring.context.beans.post-process\");// Invoke factory processors registered as beans in the context.// 在这里把beandefinition加载invokeBeanFactoryPostProcessors(beanFactory);// ......}}
现在这个类的BeanDefinition准备好了,那什么时候会创建AnnotationAwareAspectJAutoProxyCreator这个实例,然后加载到容器里呢?
我们看一下这个类的继承关系,发现它是一个实现了BeanPostProcessor接口,也就是说它是一个后置处理器。在refresh()方法中有一个步骤是专门用来注册后置处理器的,也就是registerBeanPostProcessors()这个方法。
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start(\"spring.context.refresh\");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start(\"spring.context.beans.post-process\");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 在这里把BeanPostProcessor加载到容器中registerBeanPostProcessors(beanFactory);// ......}}
在调试的过程中,发现在PostProcessorRegistrationDelegate这个类下的registerBeanPostProcessors()这个方法下会创建AnnotationAwareAspectJAutoProxyCreator,并把它注册到容器中,如下图。
PostProcessorRegistrationDelegate类下public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {}
经过上面的一个讨论,我总结了一下它的一些关键触发路径,如下:
refresh() -> invokeBeanFactoryPostProcessors() -> AspectJAutoProxyRegistrar.registerBeanDefinitions()
name:\"org.springframework.aop.config.internalAutoProxyCreator\" beanDefinition:AnnotationAwareAspectJAutoProxyCreator
-> registerBeanPostProcessors() -> 创建类实例并加载到容器中
什么时候会创建代理对象?
容器里有了AnnotationAwareAspectJAutoProxyCreator这个实例,它具体有什么用呢,它什么时候会生成代理对象呢?
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, \"Invocation of init method failed\", ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanNa2b60me);}return wrappedBean;}
大家都知道,Spring在创建一个类实例后,会对这个类进行初始化,然后会执行一系列的后置处理器,就在applyBeanPostProcessorsAfterInitialization()这个方法里面。
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
它会依次地去调用每一个后置处理器,当然也包括了我们刚刚注册的AnnotationAwareAspectJAutoProxyCreator这个后置处理器,具体的执行方法就是postProcessAfterInitialization();
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}
我们来看一下AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization这个方法,发现如果没有包装过,就把它包装一下。
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;}
return wrapIfNecessary(bean, beanName, cacheKey);
我们看到它会获取一些适配这个类的Advices和Advisors,如果不为null,就创建一个代理对象。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// DO_NOT_PROXY = 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;}
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {// ......return proxyFactory.getProxy(targetClassLoader);}
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}
Spring AOP有两种代理类,Jdk代理类和Cglib代理类,具体要看proxyTargetClass这个配置项和这个类是否实现了接口。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (!NativeDetector.inNativeImage() &&(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动态代理为例,发现它就是用Java的api进行创建的,代理类JdkDynamicAopProxy这个类
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {@Overridepublic Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) {logger.trace(\"Creating JDK dynamic proxy: \" + this.advised.getTargetSource());}return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);}}
到现在,我们知道,当创建一个bean实例后,在它初始化后,会调用每个后置处理器的初始化后的方法
当调用AOP的后置处理器的时候,会根据有没有适配它的advice和advitor来创建代理类
创建代理类的时候,有两种选择,一是JDK代理类,二是Cglib代理类
如果proxyTargetClass为false或者这个类没有实现接口的话,就选择Cglib代理类,否则选择JDK代理类。
方法执行时怎么实现拦截的?
现在我们获取一个bean时,获取的就是它的代理类,那在调用其方法时,哪些符合的通知是怎么一步步执行的呢?
我们以JDK代理类为例,我们都知道,在JDK动态代理中,实际执行的时候是执行的代理类的invoke方法,所以看一下它的具体内容:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {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 {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}else if (method.getDeclaringClass() == DecoratingProxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config.return AopProxyUtils.ultimateTargetClass(this.advised);}else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {// Service invocations on ProxyConfig with the proxy config...return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;// 如果设置了exposeProxy参数// 这里暴露了代理对象// AopContext.currentProxy() 获得if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// Get as late as possible to minimize the time we \"own\" the target,// in case it comes from a pool.target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// Get the interception chain for this method.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.if (chain.isEmpty()) {// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// We need to create a method invocation...MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.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())) {// 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);}}}}
总的看下来,主要关心以下内容:
// 如果设置了exposeProxy参数// 这里暴露了代理对象// AopContext.currentProxy() 获得if (this.advised.exposeProxy) {// Make invocation available if necessary.// 这里是用ThreadLocal实现的oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// 创建拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);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();}
这个执行链就是一个数组,然后一个一个向下执行,根据之前的例子,这个生成的执行链如下:
AspectJAroundAdvice MethodBeforeAdviceInterceptor AspectJAftad8erAdvice AspectJAfterReturningAdvice
最终包装成ReflectiveMethodInvocation这个类,调用其proceed()方法执行,如下:
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {public Object proceed() throws Throwable {// 拦截器链中的最后一个拦截器执行完if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 执行目标方法return invokeJoinpoint();}// 每次执行新的拦截器,下标+1Object 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 {// 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.// 上面的例子每次都会这个方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}}
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {public Object invoke(MethodInvocation mi) throws Throwable {if (!(mi instanceof ProxyMethodInvocation)) {throw new IllegalStateException(\"MethodInvocation is not a Spring ProxyMethodInvocation: \" + mi);}ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);JoinPointMatch jpm = getJoinPointMatch(pmi);// 调用通知的方法return invokeAdviceMethod(pjp, jpm, null, null);}}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {public Object invoke(MethodInvocation mi) throws Throwable {// 调用通知方法this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());// 下一个拦截器return mi.proceed();}}
public class AspectJAfterAdvice extends AbstractAspectJAdviceimplements MethodInterceptor, AfterAdvice, Serializable {public Object invoke(MethodInvocation mi) throws Throwable {try {// 下一个拦截器return mi.proceed();}finally {// 调用通知方法invokeAdviceMethod(getJoinPointMatch(), null, null);}}}
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {implements MethodInterceptor, AfterAdvice, Serializable {public Object invoke(MethodInvocation mi) throws Throwable {// 下一个拦截器Object retVal = mi.proceed();// 调用通知方法this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}}
===== Around before ========== Before =====do service===== AfterReturning ========== After ========== Around after =====
从上面可以看出,代理类执行的时候,就是将符合的advice排序得到一个数组,然后依次的进行执行。
总结
- 从EnableAspectJAutoProxy注解入手,Spring会注册AnnotationAwareAspectJAutoProxyCreator这个类
- AnnotationAwareAspectJAutoProxyCreator是个BeanPostProcessor,在初始化后,会调用后置处理器,生成代理对象
- 在类执行方法时,会生成一个数组,然后将所有相关的通知一个一个的执行
问题
我看看到上面的顺序是
AspectJAroundAdvice MethodBeforeAdviceInterceptor AspectJAfterAdvice AspectJAfterReturningAdvice
但是好多文章都说是
AspectJAfterReturningAdvice AspectJAfterAdvice AspectJAroundAdvice MethodBeforeAdviceInterceptor
不同的执行顺序会对你的程序会有不同的影响
后续将会写一篇文章专门介绍这个原因
参考
Spring AOP
SpringAop源码分析(基于注解) 一
SpringAop源码分析(基于注解) 三
SpringAop源码分析(基于注解)四
Spring AOP执行顺序