代码Github地址:https://github.com/abelzha/spring-framework
代码包含springframework 5.2.0.BUILD-SNAPSHOT版本源码
1. 示例代码
业务类aspectdemo.Person.java
package aspectdemo;
import org.springframework.stereotype.Component;
@Component
public class Person{
private String name;
public String getPersonName(){
System.out.println("-------getPersonName-------:"+ name);
return name;
}
public boolean setPersonName(String name){
System.out.println("--------setPersonName------:"+name);
this.name = name;
return true;
}
}
切面类aspectdemo.PersonServiceLogAspect.java
package aspectdemo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class PersonServiceLogAspect {
@Pointcut("execution(* aspectdemo.Person.*(..))")
public void Log(){
}
@Before("Log()")
public void getLogBefore(JoinPoint point){
System.out.println(point.getSignature().getName()+"-----getLogBefore,params:"+ Arrays.asList(point.getArgs()));
}
@AfterReturning(value = "Log()", returning ="result")
public void getLogAfter(JoinPoint point, Object result){
System.out.println(point.getSignature().getName()+"------getLogAfter,result:"+ result);
}
}
配置类aspectdemo.AspectAppConfig.java
package aspectdemo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy
@Configuration
@ComponentScan("aspectdemo")
public class AspectAppConfig{
}
启动类aspectdemo.AspectMain.java
package aspectdemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class AspectMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectAppConfig.class);
System.out.println(Arrays.asList(context.getBeanFactory().getBeanDefinitionNames()).toString().replaceAll(",", "\n"));
Person person = context.getBean(Person.class);
person.setPersonName("KAKA");
context.close();
}
}
以上是全部的示例代码,主要分析的有两点:
1、配置类上的注解@EnableAspectJAutoProxy做了什么?
2、启动类中person.setPersonName(“KAKA”);调用时,怎样执行了切点方法?
分析完以上两点就能大致了解AOP是如何工作的。
2.配置类上的注解@EnableAspectJAutoProxy做了什么?
1.@EnableAspectJAutoProxy导入了AspectJAutoProxyRegistrar.class。而该类中只有一个方法org.springframework.context.annotation.AspectJAutoProxyRegistrar#registerBeanDefinitions
,老方法,打断点,查看容器启动时的调用栈。
调用过程:
-
1.容器创建,调用容器刷新接口refresh();
-
2.调用工厂后置处理器方法invokeBeanFactoryPostProcessors(beanFactory);
-
3.被org.springframework.context.annotation.internalConfigurationAnnotationProcessor这个工厂的后置处理器处理,调用工厂后置处理器的方法:postProcessor.postProcessBeanDefinitionRegistry(registry);
-
4.通过ConfigurationClassParser parser解析器来解析每一个@Configuration配置类,获取配置类中解析到的所有bean;
Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); -
5.从配置类中加载导入的BeanDefinitionRegistrars信息。loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
-
6.创建注册AspectJAnnotationAutoProxyCreator, AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
至此,注解@EnableAspectJAutoProxy就是在容器中注册了一个AspectJAnnotationAutoProxyCreator。
AspectJAnnotationAutoProxyCreator ——>AbstractAdvisorAutoProxyCreator ——> AbstractAutoProxyCreator ---->SmartInstantiationAwareBeanPostProcessor ——>InstantiationAwareBeanPostProcessor ——>BeanPostProcessor
接下就是Person实例创建过程中,AspectJAnnotationAutoProxyCreator做了哪些事情?通过之前的分析我们得知了它是一个beanPostProcessor。所以它的调用时机也许我们能猜得到。
接下来,同样查看调用栈
有调用栈得知在实例化bean之后调用bean的后置处理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
上面代码就会调用AspectJAnnotationAutoProxyCreator
的父类org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
的方法wrapIfNecessary。
1.得到bean中的切面(getAdvicesAndAdvisorsForBean),有两个是我们添加的,一个是容器默认添加的。
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
2.通过new ProxyFactory();得到代理对象
- 包装切面的allInterceptors得到bean中的增强器advisors;
- 通过 return new ObjenesisCglibAopProxy(config);得到代理对象;
- 返回wrappedBean,注册到容器中
以上,分析了注解@EnableAspectJAutoProxy的全部功能。
3. 启动类中person.setPersonName(“KAKA”);调用时,怎样执行了切点方法?
老办法:切面方法打断点,查看调用栈
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
里面就是交给CglibAopProxy去控制MethodInterceptor和目标方法的执行。具体动态代理的详情以后再分析。