Spring AOP 機(jī)制源碼解讀
導(dǎo)讀
- AOP是Spring框架面向切面的編程思想,AOP采用一種稱為“橫切”的技術(shù)关摇,將涉及多業(yè)務(wù)流程的通用功能抽取并單獨(dú)封裝屑埋,形成獨(dú)立的切面,在合適的時(shí)機(jī)將這些切面橫向切入到業(yè)務(wù)流程指定的位置中惋嚎。
- 本文不會(huì)講解Spring切面的使用方法以及Spring切面的定義杠氢,但會(huì)通過一個(gè)示例引入話題。
- 本文設(shè)計(jì)內(nèi)容主要說明Spring內(nèi)部如何幫我們做切面處理另伍,Spring是如何實(shí)現(xiàn)切面的鼻百,雖然Spring切面的底層實(shí)現(xiàn)還是基于動(dòng)態(tài)代理,但是本文并不會(huì)講解動(dòng)態(tài)代理摆尝,如果讀者不太了解動(dòng)態(tài)代理温艇,還需先連接器原理后再進(jìn)行本文的解讀,本文解讀需要一定的基礎(chǔ):如Spring bean的加載機(jī)制堕汞,Spring注解功能勺爱,Spring后置處理器,Spring BeanFactory讯检。
一 示例引入
1.1 目標(biāo)方法
下面是測試所用的目標(biāo)方法琐鲁,使用如下一個(gè)打印方法進(jìn)行測試:
方法很簡單,參入兩個(gè)int類型的輸入?yún)?shù)人灼,打印入?yún)⑽Ф危祷貎蓚€(gè)參數(shù)的除;
我們的需求是:在目標(biāo)方法運(yùn)行的時(shí)候進(jìn)行日志輸出(方法運(yùn)行前投放,方法運(yùn)行結(jié)束奈泪,或者方法運(yùn)行出現(xiàn)異常的時(shí)候,...)
public class MainPrint {
public int print(int i, int j) {
System.out.println("i = " + i + ", j = " + j);
return i / j;
}
}
1.2 定義切換類
定義切面如下所示:
- 通過注解@Aspect告知Spring 該類是一個(gè)切面類跪呈。
- 定義前置增加(@Before):logStart:在目標(biāo)方法(div)運(yùn)行之前運(yùn)行
- 定義后置通知(@After):logEnd:在目標(biāo)方法(div)運(yùn)行結(jié)束之后運(yùn)行(無論方法正常結(jié)束還是異常結(jié)束)
- 返回通知(@AfterReturning):logReturn:在目標(biāo)方法(div)正常返回之后運(yùn)行
- 異常通知(@AfterThrowing):logException:在目標(biāo)方法(div)出現(xiàn)異常以后運(yùn)行
- 環(huán)繞通知(@Around):動(dòng)態(tài)代理段磨,手動(dòng)推進(jìn)目標(biāo)方法運(yùn)行(joinPoint.procced());
@Aspect
public class LogsAspects {
/**
* 定義切入點(diǎn)
*/
@Pointcut("execution(public int org.mzw.spring.annotation.aop.MainPrint.*(..))")
public void pointCut(){};
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(""+joinPoint.getSignature().getName()+"運(yùn)行耗绿。苹支。。@Before:參數(shù)列表是:{"+Arrays.asList(args)+"}");
}
@After("org.mzw.spring.annotation.aop.LogsAspects.pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(""+joinPoint.getSignature().getName()+"結(jié)束误阻。债蜜。晴埂。@After");
}
/**
* 獲取返回值
* 注意:JoinPoint一定要出現(xiàn)在參數(shù)表的第一位
*/
@AfterReturning(value="pointCut()",returning="result")
public void logReturn(JoinPoint joinPoint,Object result){
System.out.println(""+joinPoint.getSignature().getName()+"正常返回。寻定。儒洛。@AfterReturning:運(yùn)行結(jié)果:{"+result+"}");
}
@AfterThrowing(value="pointCut()",throwing="exception")
public void logException(JoinPoint joinPoint,Exception exception){
System.out.println(""+joinPoint.getSignature().getName()+"異常。狼速。琅锻。異常信息:{"+exception+"}");
}
}
1.3 基于注解配置
- @EnableAspectJAutoProxy 通過添加該注解告知Spring啟動(dòng)AspectJAutoProxy 開啟基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class ConfigOfAOP {
//業(yè)務(wù)邏輯類加入容器中
@Bean
public MainPrint calculator(){
return new MainPrint();
}
//切面類加入到容器中
@Bean
public LogsAspects logsAspects(){
return new LogsAspects();
}
}
1.4 Main 啟動(dòng)容器
private static void starterSpringOfAop(Class<?>... clazz) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(clazz);
MainPrint bean = applicationContext.getBean(MainPrint.class);
int print = bean.print(2, 4);
System.out.println(print);
}
輸出結(jié)果:
print運(yùn)行。向胡。恼蓬。@Before:參數(shù)列表是:{[2, 4]}
i = 2, j = 4
print結(jié)束。僵芹。处硬。@After
print正常返回。拇派。荷辕。@AfterReturning:運(yùn)行結(jié)果:{0}
0
實(shí)例很簡單,接下類看看這簡單的背后Spring是如何處理的件豌。
在上面示例中疮方,@Aspect告知Spring這是一個(gè)切面邏輯,只有另一處代碼我們需要關(guān)注苟径,那就是@EnableAspectJAutoProxy 該注解告知Spring 開啟切面功能案站。
所以我們需要重點(diǎn)關(guān)注下@EnableAspectJAutoProxy到底做了哪些騷操作
躬审。
二 AOP代理創(chuàng)建源碼解讀
開啟基于注解的aop模式棘街;@EnableAspectJAutoProxy
了解Spring IOC的可以知道,Spring在啟動(dòng)的時(shí)候會(huì)注冊一些Bean承边,不同的Bean在不同的時(shí)機(jī)做不同的事情遭殉,所以我們也效仿這個(gè)模板去分析下Spring的AOP原理(容器中注冊了什么組件,這個(gè)組件什么時(shí)候工作博助,這個(gè)組件的功能是什么险污?)
2.1 EnableAspectJAutoProxy
2.1.1 @EnableAspectJAutoProxy 是什么?
我們在Spring的配置類上添加了這一注解@EnableAspectJAutoProxy 富岳,所以我們先分析下這個(gè)注解到底是做什么的蛔糯?
下面是EnableAspectJAutoProxy的源碼:這個(gè)是一個(gè)注解組件,除了注解常用的幾個(gè)用于注解的注解之外我們會(huì)發(fā)現(xiàn)一個(gè)特殊的注解@Import(AspectJAutoProxyRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
@Import 該組件可以向容器中注冊Bean,
- {@link Configuration},
- {@link ImportSelector},
- {@link ImportBeanDefinitionRegistrar} * or regular component classes to import.
我們看到AspectJAutoProxyRegistrar
應(yīng)該是一個(gè)BeanDefinitionRegistrar, 給容器中導(dǎo)入AspectJAutoProxyRegistrar
2.1.2 AspectJAutoProxyRegistrar.class
利用AspectJAutoProxyRegistrar
自定義給容器中注冊bean窖式;BeanDefinetion
源碼如下:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
2.1.3 registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
查看方法最終是給容器中注冊一個(gè)AnnotationAwareAspectJAutoProxyCreator.class
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
2.1.4 @EnableAspectJAutoProxy 注解小結(jié)
- @EnableAspectJAutoProxy :利用
@Import
給容器中導(dǎo)入AspectJAutoProxyRegistrar
; - 利用AspectJAutoProxyRegistrar自定義給容器中注冊bean蚁飒;
AnnotationAwareAspectJAutoProxyCreator
所以@EnableAspectJAutoProxy 注解的功能最終就是給Spring Ioc容器中注冊了一個(gè)Bean:AnnotationAwareAspectJAutoProxyCreator
2.2 AnnotationAwareAspectJAutoProxyCreator
我們先分析下AnnotationAwareAspectJAutoProxyCreator 這是一個(gè)什么組件,看下該類的繼承關(guān)系:如下圖(簡化后的:排除一些無關(guān)此話題的依賴樹):
上圖中關(guān)注標(biāo)紅的組件:
- implements SmartInstantiationAwareBeanPostProcessor 后置處理器
- BeanFactoryAware 自動(dòng)裝配BeanFactory
知道了這個(gè)組件是一個(gè)什么東西后我們就可以分析它具體做什么事情萝喘?
- 關(guān)注后置處理器淮逻,在bean初始化完成前后做事情琼懊?
- 裝配BeanFactory
這里暫時(shí)不說SpringIOC是如何加載AnnotationAwareAspectJAutoProxyCreator的邏輯,這里暫時(shí)只分析AnnotationAwareAspectJAutoProxyCreator的作用爬早,后續(xù)有機(jī)會(huì)再針對(duì)Spring加載AnnotationAwareAspectJAutoProxyCreator進(jìn)行說明哼丈。
2.2.1 AbstractAutoProxyCreator
在該AnnotationAwareAspectJAutoProxyCreator組件的超類AbstractAutoProxyCreator 中顯示的裝配了BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
同時(shí)在該AbstractAutoProxyCreator組件中實(shí)現(xiàn)了后置處理器的邏輯
此處需要特殊說明下:
- 一般我們實(shí)現(xiàn)BeanPostProcess 實(shí)現(xiàn)的方法是postProcessBeforeInitialization/postProcessAfterInitialization,該方法是Bean在調(diào)用初始化方法前后被調(diào)用,
- 而此處我們實(shí)現(xiàn)InstantiationAwareBeanPostProcessor的方法是postProcessBeforeInstantiation/postProcessAfterInstantiation 該方法是在Bean實(shí)例化的前后進(jìn)行調(diào)用筛严;
補(bǔ)充說明:AbstractAutoProxyCreator實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor 所以AnnotationAwareAspectJAutoProxyCreator組件的作用是在每個(gè)Bean創(chuàng)建之前調(diào)用postProcessBeforeInstantiation()
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
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;
}
2.2.2 方法 postProcessBeforeInstantiation
該方法一直跳過醉旦,所以此處不進(jìn)行分析
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
2.2.3 postProcessAfterInitialization
- 嘗試從緩存中獲取bean名稱
- 是否是早期代理引用
- 如果不是則進(jìn)行增強(qiáng)嘗試
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
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;
}
關(guān)注該方法wrapIfNecessary 見名知意: 如果需要?jiǎng)t進(jìn)行增強(qiáng),
2.2.3 wrapIfNecessary
- 判斷當(dāng)前bean是否在advisedBeans中(保存了所有需要增強(qiáng)bean)
- 判斷當(dāng)前bean是否是基礎(chǔ)類型的Advice桨啃、Pointcut髓抑、Advisor、AopInfrastructureBean优幸, 或者是否是切面(@Aspect)
- 是否需要跳過
- 獲取候選的增強(qiáng)器(切面里面的通知方法)【List<Advisor> candidateAdvisors】每一個(gè)封裝的通知方法的增強(qiáng)器是 InstantiationModelAwarePointcutAdvisor吨拍;判斷每一個(gè)增強(qiáng)器是否是 AspectJPointcutAdvisor 類型的;返回true
- 永遠(yuǎn)返回false
- 創(chuàng)建代理對(duì)象
- 放入緩存
- 返回代理對(duì)象
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
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);
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 創(chuàng)建代理對(duì)象
下面是createProxy 調(diào)用鏈
return proxyFactory.getProxy(getProxyClassLoader());
- getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
- createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
- getAopProxyFactory().createAopProxy
DefaultAopProxyFactory#createAopProxy
這里判斷使用哪種進(jìn)行代理 - 如果目標(biāo)對(duì)象實(shí)現(xiàn)接口网杆,使用JDK動(dòng)態(tài)代理技術(shù) -> new JdkDynamicAopProxy(config);
- 如果目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口羹饰,則使用cglib動(dòng)態(tài)代理技術(shù) -> new ObjenesisCglibAopProxy(config);
@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);
}
}
然后調(diào)用具體實(shí)現(xiàn)的代理工廠的getProxy 創(chuàng)建代理,
下面是CglibAopProxy的getProxy方法實(shí)現(xiàn):
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, 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 ClassLoaderAwareUndeclaredThrowableStrategy(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);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
返回代理對(duì)象
到此代理對(duì)象創(chuàng)建完畢碳却!
AOP 代理方法執(zhí)行邏輯源碼解析
代碼中我們獲取代理對(duì)象队秩,并執(zhí)行目標(biāo)方法
bean.print(2, 4);
private static void starterSpringOfAop(Class<?>... clazz) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(clazz);
MainPrint bean = applicationContext.getBean(MainPrint.class);
int print = bean.print(2, 4);
System.out.println(print);
}
這里我們斷點(diǎn)打在bean.print(2, 4); 觀察下
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) {
// 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);
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 && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
2.3.1 核心代碼CglibMethodInvocation.proceed
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
Object[] arguments, @Nullable Class<?> targetClass,
List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
// Only use method proxy for public methods not derived from java.lang.Object
this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
methodProxy : null);
}
2.3.2 proceed
執(zhí)行步驟:
- 容器中保存了組件的代理對(duì)象(cglib增強(qiáng)后的對(duì)象)宪郊,這個(gè)對(duì)象里面保存了詳細(xì)信息(比如增強(qiáng)器泞边,目標(biāo)對(duì)象,xxx)燥翅;
- 根據(jù)ProxyFactory對(duì)象獲取將要執(zhí)行的目標(biāo)方法攔截器鏈关噪;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- List<Object> interceptorList保存所有攔截器 : 一個(gè)默認(rèn)的ExposeInvocationInterceptor 和 4個(gè)增強(qiáng)器鸟蟹;
- 遍歷所有的增強(qiáng)器,將其轉(zhuǎn)為Interceptor使兔;registry.getInterceptors(advisor);
- 將增強(qiáng)器轉(zhuǎn)為List<MethodInterceptor>建钥;如果是MethodInterceptor,直接加入到集合中,如果不是虐沥,使用AdvisorAdapter將增強(qiáng)器轉(zhuǎn)為MethodInterceptor熊经;轉(zhuǎn)換完成返回MethodInterceptor數(shù)組;
- 如果沒有攔截器鏈欲险,直接執(zhí)行目標(biāo)方法;攔截器鏈(每一個(gè)通知方法又被包裝為方法攔截器镐依,利用MethodInterceptor機(jī)制)
- 如果有攔截器鏈,把需要執(zhí)行的目標(biāo)對(duì)象槐壳,目標(biāo)方法,攔截器鏈等信息傳入創(chuàng)建一個(gè) CglibMethodInvocation 對(duì)象,并調(diào)用 Object retVal = mi.proceed();
- 攔截器鏈的觸發(fā)過程; 如果沒有攔截器執(zhí)行執(zhí)行目標(biāo)方法,或者攔截器的索引和攔截器數(shù)組-1大小一樣(指定到了最后一個(gè)攔截器)執(zhí)行目標(biāo)方法特幔;鏈?zhǔn)将@取每一個(gè)攔截器薄风,攔截器執(zhí)行invoke方法横辆,每一個(gè)攔截器等待下一個(gè)攔截器執(zhí)行完成返回以后再來執(zhí)行炫惩;攔截器鏈的機(jī)制芭毙,保證通知方法與目標(biāo)方法的執(zhí)行順序侈百;
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
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 {
// 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);
}
}