1.AOP是什么
网络上很多解释,本文不在赘述,大致意思就好比,比如你一个月前开发了一个代码,功能就是一个除法功能,而现在,你想在原有除法功能基础上,记录传入的参数(除数,被除数)到数据库,并且在除法功能完成后,记录一下返回值到数据库。按照以前的逻辑是需要到这个除法功能里面,修改原有代码。当然,这个除法功能相对比较简单,修改原有代码不复杂,但是实际生产上的业务肯定是比这个复杂的多,改代码的风险也是不可预计的。在设计模式有一种原则就是开闭原则,对修改关闭,对扩展开放,也是为了规避这一风险,所以spring的Aop很好的做到了这一点。
2.如何使用AOP
引入spring和springAop还有junit的相关jar包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringDemo</groupId>
<artifactId>SpringDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
</dependencies>
</project>
定义配置类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.erwan.cap12.Bean")
public class Cap12MainConfigAop {
@Bean
public Calculator calculator() {
return new Calculator();
}
@Bean
public CalculatorAop calculatorAop() {
return new CalculatorAop();
}
}
其中EnableAspectJAutoProxy注解就是开启AOP功能
//原有代码,提供除法功能的类
public class Calculator {
public int div(final int i, final int j) {
System.out.println("--------");
return i / j;
}
}
定义一个切面类,来扩展Calculator
@Aspect
public class CalculatorAop {
@Around("pointCut()")
public Object AroundCalculator(final ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
System.out.println("@Around:执行目标方法之前...");
Object obj = proceedingJoinPoint.proceed();// 相当于开始执行div
System.out.println("@Arountd:执行目标方法之后...");
return obj;
}
@Before("pointCut()")
public void logBefore(final JoinPoint joinPoint) {
System.out.println("div开始前" + Arrays.asList(joinPoint.getArgs()));
}
@After("pointCut()")
public void logEnd(final JoinPoint joinPoint) {
System.out.println("div开始后" + Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()", throwing = "ex")
public void logException(final Exception ex) {
System.out.println("div发生异常" + ex.getMessage());
}
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(final Object result) {
System.out.println("div返回值" + result);
}
@Pointcut("execution(public * com.erwan.cap12.Bean.Calculator.*(..))")
public void pointCut() {
}
}
测试类:
@Test
public void cap12() {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Cap12MainConfigAop.class);
Calculator bean = context.getBean(Calculator.class);
bean.div(4, 2);
}
测试结果如下:
@Around:执行目标方法之前...
div开始前[4, 2]
Calculator自己运行的div
@Arountd:执行目标方法之后...
div开始后[4, 2]
div返回值2
所以使用aop就以下三步
1,将业务逻辑组件和切面类都加入到容器中, 告诉spring哪个是切面类(@Aspect)
2,在切面类上的每个通知方法上标注通知注解, 告诉Spring何时运行(写好切入点表达式,参照官方文档)
3,开启基于注解的AOP模式 @EnableAspectJAutoProxy
SpringAOP可以应用5种类型的通知:
1.前置通知(Before):在目标方法被调用之前调用通知功能。
2.后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
3.返回通知(After-returning):在目标方法成功执行之后调用通知。
4.异常通知(After-throwing):在目标方法抛出异常后调用通知。
5.环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
其中环绕通知比较特殊,他可以在注解的方法体(AroundCalculator)定义是否执行目标方法,如果不执行,则After 和After-returning则不生效,他也可以在捕捉到异常后,重新执行目标方法(div),功能比较强大
其中@Pointcut就是定义需要拦截或者说增强的目标类和目标类的方法,其中 Calculator.*(..)代表 Calculator类的所有方法就是增强所有方法的调用。
使用JoinPoint可以拿到相关的内容, 比如方法名, 参数
aop源码解读
在aop的使用中我们提到,如何使用Aop
1,将业务逻辑组件和切面类都加入到容器中, 告诉spring哪个是切面类(@Aspect)
2,在切面类上的每个通知方法上标注通知注解, 告诉Spring何时运行(写好切入点表达式,参照官方文档)
3,开启基于注解的AOP模式 @EnableAspectJAutoProxy
这里我们需要从配置类的注解@EnableAspectJAutoProxy入手,打开这个注解显示如下:
//导入了此类,点进去看
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
//proxyTargetClass属性,默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采
用CGLIB动态代理织入增强
boolean proxyTargetClass() default false;
//通过aop框架暴露该代理对象,aopContext能够访问
boolean exposeProxy() default false;
}
这个注解里面 包括两点,@Import注解和 proxyTargetClass参数
其中proxyTargetClass默认为false,就用cglib来代理增强,如果为true则通过jdk来动态代理增强
cglib和jdk的动态代理这里可以参考我的另外一篇文章解密动态代理,cglib和jdk动态代理
@Import功能也可以参考二万的另外一篇文章深入理解 @Import注解
@Import就是可以在容器中注入bean,也可以实现ImportBeanDefinitionRegistrar接口,通过实现ImportBeanDefinitionRegistrar接口来拿到BeanDefinitionRegistry,然后通过 BeanDefinitionRegistry 向ioc容器中注册bean。
通过@Import看到,引入了AspectJAutoProxyRegistrar
接下来我们来看看AspectJAutoProxyRegistrar这个类,它实现了ImportBeanDefinitionRegistrar。
实现这个接口ImportBeanDefinitionRegistrar可以在它原有的方法registerBeanDefinitions中得到 BeanDefinitionRegistry registry, 这个registry可以把具体的bean注入到容器中。
/*
*实现了ImportBeanDefinitionRegistrar这个接口,并且可以通过重写其registerBeanDefinitions方法
*拿到BeanDefinitionRegistry registry ,然后通过registry向ioc容器中注册bean。
*
*/
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) {
//这行代码的功能就是,通过registry向ioc容器中注入AnnotationAwareAspectJAutoProxyCreator 这个bean
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);
}
}
}
}
接下来我们看 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这行代码持续跟进,进入AopConfigUtils类,最后走到BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) ,实现向ioc容器注入bean。(实现原理可以看上面的@Import功能)
@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,然后注册bean。
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注册了一个bean名称为AUTO_PROXY_CREATOR_BEAN_NAME,
//类为 AnnotationAwareAspectJAutoProxyCreator的bean
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
AUTO_PROXY_CREATOR_BEAN_NAME 是常量,值为:org.springframework.aop.config.internalAutoProxyCreator
所以总的来说就是注册了一个bean名称为org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator.class
接下来 我们看 AnnotationAwareAspectJAutoProxyCreator这个类
它的顶层就是BeanPostProcessor,beanPostProcessor就是bean的后置处理器,通俗来说就是在一个普通bean(Calculator)创建后,为这个Calculator做一些其他事,比如说通过动态代理来增强这个bCalculatoran。可以参考解密动态代理,cglib和jdk动态代理
在阅读源码后,发现在bean的生命周期中,是先创建Calculator,然后赋值,然后初始化Calculator,也就是在初始化Calculator的时候通过动态代理对beanCalculator增强。
bean的生命周期可以得到如下内容:
ioc容器通过构造函数创建Calculator
populateBean(beanName, mbd, instanceWrapper); 对Calculator属性赋值,如果有
exposedObject = initializeBean(beanName, exposedObject, mbd); 初始化Calculator
initializeBean 的内部包括以下3点
1.invokeAwareMethods()对实现了 aware的接口,调用对应的方法得到对应的bean,比如实现beanFactoryAware可以得到beanFactory,具体可以参考Spring Aware接口的奇妙用处
2.applyBeanPostProcessorsBeforeInitialization
3.nvokeInitMethods 在构造器后调用的方法 InitializingBean. afterPropertiesSet 之后invokeCustomInitMethod 调用初始化方法
4.执行AbstractAutoProxyCreator.postProcessBeforeInstantiation //这里实现动态代理创建对象
bean的生命周期是通过阅读源码得到的,以上只是总结,具体可以参考spring bean的生命周期
下面我们来研究bean在初始化的时候,如何调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation这个内容,又是如何实现动态代理对象的创建的。
在初始化Calculate的时候是如何调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation 这个呢,下面截取部分源码
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
通过前面我们对@EnableAspectJAutoProxy开启aop功能的注解时候,得到通过@Import向 ioc容器中注入了AnnotationAwareAspectJAutoProxyCreator这个类,并且这个类实现了BeanPostPRocessor,所以是所以这个类可以在容器中通过getBeanPostProcessors得到的。
通过多态的原理我们可以知道调用BeanPostProcessor.postProcessBeforeInitialization可以调用到具体实现类的方法。
而AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator,所以最后调用到的是
AbstractAutoProxyCreator.postProcessBeforeInstantiation
我们接下来看看AbstractAutoProxyCreator.postProcessBeforeInstantiation到底做了什么
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
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;
}
这里可以看到,这个方法做了两个内容,
一是得到所有的通知advices,也就是得到CalculatorAop 中 @AfterThrowing,@AfterReturing,@before @@Around这些注解的具体内容
二就是创建动态代理对象
动态代理对象得到了,之后就是通过拦截方法,来实现aop功能。
Calculator bean = context.getBean(Calculator.class); 得到动态代理对象
调用CalCulator的div的时候,动态代理会对具体方法进行拦截,然后执行自己的特定内容。也就是调用这一行代码: bean.div(4, 2);
因为我们这里使用的Caculator类来做的aop,所以动态代理使用的cglib,接口用的是jdk动态代理
通过cglib我们可以得到在cglib的callback函数中来实现对方法div的拦截
继续研究AbstractAutoProxyCreator.postProcessBeforeInstantiation 中如何创建cglib动态代理对象(也就是cglib的增强对象)的
研究AbstractAutoProxyCreator.postProcessBeforeInstantiation方法中的 这一行 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//得到通知advices的所有内容
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建具体动态代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
我们接着看return proxyFactory.getProxy(getProxyClassLoader());这一行的具体内容
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
跟进createAopProxy()
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
最后跟踪到DefaultAopProxyFactory的 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException 这个方法
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.");
}
//是否是接口或者proxyClass为true
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
可以看到如果@EnableAspectJAutoProxy注解proxyTargetClass的属性是true或者增强对象(Calculator)是接口的话,就创建jdk动态代理。
通过我们前面看到我们@EnableAspectJAutoProxy并没有指定proxyTargetClass为true(通过查看@EanbleAspectJAutoProxy得到,默认为false):boolean proxyTargetClass() default false;
Calculator也不是接口,所以这里创建的是ObjenesisCglibAopProxy动态代理对象
我们来查看class ObjenesisCglibAopProxy extends CglibAopProxy 这个类,可以发现它是 继承CglibAopProxy。
而CglibAopProxy则是整个Calculator方法拦截的核心。
通过解密动态代理,cglib和jdk动态代理这里得到
分析cglib动态代理执行拦截的方法是当Calculator.div调用的时候,会通过设置的callBack函数(并且这个函数实现了MethodInterceptor这个接口),执行这个CallBack函数的intercept方法。
所以研究CglibAopProxy这个类最核心的地方是找到这个callBack函数和intercept方法,在二万多次调试中得到
Calculator的div方法是被CglibAopProxy的内部类DynamicAdvisedInterceptor进行拦截的
所以我们这里研究DynamicAdvisedInterceptor 的 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable方法(这里你们可以直接在这个方法内部打个断点论证一下)
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);
}
}
}
通过调试得到拦截链这个list<Object>chain中的存放顺序是
before这个通知应该是第一个执行的,为什么会是放在最后,我们接下来分析。
这个方法中,先是得到拦截链,然后通过拦截链来依次执行,达到对aop的五种类型的通知逆序序执行。如果拦截链为空,则直接通过 retVal = methodProxy.invoke(target, argsToUse);执行Calculator.div方法
这里拦截链有一个很有意思的点是,他通过多态+递归的方法,来达到先进后出,逆序执行的目的的。
就是 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 这行代码达到AOp通知的具体通知的。
我们来看看CglibMethodInvocation.proceed这个方法
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;
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.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
执行逻辑如下:
1. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}//判断 currentInterceptorIndex是否等于拦截链的长度6,这里currentInterceptorIndex初始值为-1,不等于,所以往下走
2.Object interceptorOrInterceptionAdvice=this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)获得具体拦截链的执行方法,interceptorsAndDynamicMethodMatchers这个map中获得index为0的拦截链执行方法ExposeInvocationInterceptor
3.((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)执行,ExposeInvocationInterceptor.invoke的方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法
4.继续获得具体的拦截链执行方法,获得index为1的拦截链执行方法AspectJAfterThrowingAdvice
5.执行AspectJAfterThrowingAdvice.invoke()方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
6.在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于2的拦截链执行方法AfterReturningAdviceInterceptor
7.执行AfterReturningAdviceInterceptor.invoke()
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
8.在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于3的拦截链执行方法AspectJAfterAdvice
9.执行AspectJAfterAdvice.invoke方法
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
10.执行mi.proceed方法,又调用到CglibMethodInvocation.proceed()这个方法,获得index等于4的拦截链执行方法AspectJAroundAdvice,执行AspectJAroundAdvice.invoke()方法
11..在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于5的拦截链执行方法MethodBeforeAdviceInterceptor,执行MethodBeforeAdviceInterceptor.invoke()
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
从这里看到先执行的通知方法 @Before 打印出div开始前[4, 2],然后执行的mi.proceed();又调用到
CglibMethodInvocation.proceed(),然后his.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1这个判断条件成立,进入invokeJoinpoint方法,调用到CglibAopProxy的invokeJoinpoint方法
protected Object invokeJoinpoint() throws Throwable {
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}
这个方法就最后就是调用java.refelt.Method.invoke,来达到执行Calculate.div方法,并且打印,Calculator自己运行的div,这句话。
然后开始递归的回溯,依次进行AspectJAfterAdvice,AfterReturningAdviceInterceptor,AspectJAfterThrowingAdvice,ExposeInvocationInterceptor的剩余逻辑,依次打出div开始后[4, 2],div返回值2 这些话
Aop流程如下:
1.向ioc容器注册一个bean名称为org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator.class
2.通过实现BeanPostProcessor接口,成为BeanPostProcessor。在Calculate这个bean创建后的初始化逻辑中,通过for循环遍历所有BeanPostProcessor,调用BeanPostProcessor.postProcessBeforeInstantiation来调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation这个方法,得到所有的通知,并且创建cglib动态代理对象,并且在cglib中设置的callback函数为DynamicAdvisedInterceptor,如果执行Caculator的方法,就会进入到DynamicAdvisedInterceptor拦截方法中,DynamicAdvisedInterceptor为CglibAopProxy的内部类
此时ioc容器中的Calculator这个对象就是一个增强后的对象
3.通过ioc容器得到增强后的对象 Calculator bean = context.getBean(Calculator.class);
4.调用bean.div(4, 2); 方法,被CglibAopProxy中的public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable所拦截。
5.执行retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();进入到
ReflectiveMethodInvocation.proceed()方法。利用多态和递归,逆序的实现拦截链的调用。
这里提一下,这里的多态就是,一个接口有多个实现,而调用直接用接口调用方法,在运行时jvm会根据具体接口的实例来调用具体的逻辑。
ioc容器先对Calculator进行增强,在beanCalculator增强后,将这个bean(Calculator)注入到ioc容器中,简单的说也就是放在ioc的一个总的Map中
在从ioc容器中获得Calculator的时候,就得到了增强后的Calculator。也就是调用这一行代码: Calculator bean = context.getBean(Calculator.class);
调用CalCulator的div的时候,动态代理会对具体方法进行拦截,然后执行自己的特定内容。也就是调用这一行代码: bean.div(4, 2);
所以在Calculator在容器初始化的时候,具体逻辑如下