一個例子
// 定義一個切面
package cn.eagle.li.source.aspect;
@Component
@Aspect
public 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;
@Service
public class ServiceImpl implements IService {
@Override
public 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,預設false
boolean proxyTargetClass() default false;
// 要不要暴露代理物件
boolean exposeProxy() default false;
}
除了上面兩個引數比較重要外,它還有一個Import註解,在Spring中,只要一種註解組合了另一種註解,它就具有該註解的功能,也就是這個註解擁有了@Import註解的功能。
@Import(AspectJAutoProxyRegistrar.class)
我們看到它import了AspectJAutoProxyRegistrar這個類,我們下面再看看這個類的內容,發現它主要的工作就是註冊一個name為:
org.springframework.aop.config.internalAutoProxyCreator,類為AnnotationAwareAspectJAutoProxyCreator的BeanDefinition。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// ......
}
}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
public abstract class AopConfigUtils {
@Nullable
public 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";
@Nullable
private 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 = AnnotationAwareAspectJAutoProxyCreator.class
registry.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, beanName);
}
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 {
@Override
public 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 AspectJAfterAdvice AspectJAfterReturningAdvice
最終包裝成ReflectiveMethodInvocation這個類,呼叫其proceed()方法執行,如下:
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
public Object proceed() throws Throwable {
// 攔截器鏈中的最後一個攔截器執行完
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 執行目標方法
return invokeJoinpoint();
}
// 每次執行新的攔截器,下標+1
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 {
// 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 AbstractAspectJAdvice
implements 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
不同的執行順序會對你的程式會有不同的影響
後續將會寫一篇文章專門介紹這個原因