阅读文章时,看看流程图会更容易理解哦:
https://www.processon.com/view/link/5df5e143e4b004cc9a3068d2
示例准备
在分析aop源码之前,先搭建一个demo示例,演示下效果。
比如,有一个DemoService接口,里面定义一个demo方法:
public interface DemoService {
void demo(String args);
}
给他一个简单的实现:
@Component
public class DemoServiceImpl implements DemoService{
@Override
public void demo(String args) {
System.out.println("-----DemoServiceImpl.demo()-----");
// throw new RuntimeException();
}
}
接下来,使用一个切面类来封装切面的逻辑,比如来一个日志切面,使用@Aspect注解标明它是一个切面类:
@Component
@Aspect
public class DemoLogAspect {
//切点表达式,表示要切DemoService下的所有方法
@Pointcut("execution(* com.zyy.sc.analysis.framework.debugAopAspect.DemoService.*(..))")
public void pointCut(){}
//前置通知,在执行目标方法前执行
@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("拦截到目标方法:"+methodName+", 方法参数:"+args+",执行【前置通知】逻辑");
}
//后置通知,在执行目标方法后执行
@After("pointCut()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("拦截到目标方法:"+methodName+", 方法参数:"+args+",执行【后置通知】逻辑");
}
//返回通知,在执行目标方法成功后执行
@AfterReturning("pointCut()")
public void afterReturningMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("拦截到目标方法:"+methodName+", 方法参数:"+args+",执行【返回通知】逻辑");
}
//异常通知,在执行目标方法异常后执行
@AfterThrowing("pointCut()")
public void afterThrowingMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("拦截到目标方法:"+methodName+", 方法参数:"+args+",执行【异常通知】逻辑");
}
//环绕通知,.....
}
在配置类中,注意要使用@EnableAspectJAutoProxy注解来启用aop的自动代理机制:
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class MainConfig {
}
最后,我们使用Main方法来测试:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
context.getBean(DemoService.class).demo("args");
context.registerShutdownHook();
}
}
控制台输出:
拦截到目标方法:demo, 方法参数:args,执行【前置通知】逻辑
-----DemoServiceImpl.demo()-----
拦截到目标方法:demo, 方法参数:args,执行【后置通知】逻辑
拦截到目标方法:demo, 方法参数:args,执行【返回通知】逻辑
@EnableAspectJAutoProxy 干了什么
在使用spring的过程中,时常会引入一些组件,如果要启用这些组件的话,通常需要我们配置下@EnableXXX,那么这个注解原理是什么,以@EnableAspectJAutoProxy为例说明一下。
进入EnableAspectJAutoProxy注解的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
可以看到,其实它是用@Import注解标注的,“Spring框架IOC容器初始化核心源码解析之三:BeanDefinition注册”文章中的说明,在解析配置类(doProcessConfigurationClass方法)的过程中,会处理@Import注解,具体的处理过程这儿不重复了。
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
我们可以来看下getImports方法,它会调用collectImports方法,这个方法会扫描解析类的所有注解,并递归解析注解的注解,因此只要有@Import,都会被找出来,然后从里面找到value值。
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
对于@EnableAspectJAutoProxy注解,会找到AspectJAutoProxyRegistrar这个类,这个类是ImportBeanDefinitionRegistrar,spring会调用registerBeanDefinitions方法,这个方法中,它会注册一个AnnotationAwareAspectJAutoProxyCreator类的beanDefinition。
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//注册AnnotationAwareAspectJAutoProxyCreator这个类的beanDefinition
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//设置AnnotationAwareAspectJAutoProxyCreator这个类的beanDefinition的属性
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
因此,@EnableXXX的注解,通常使用了@Import注解标注了,作用是往容器中注册自己的组件。
创建代理对象准备
在createBean方法中,有这样一段逻辑:
//这儿会调用InstantiationAwareBeanPostProcessor的 postProcessBeforeInstantiation
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
而在前面,我们注册的 AnnotationAwareAspectJAutoProxyCreator 它就实现了InstantiationAwareBeanPostProcessor, 其postProcessBeforeInstantiation方法,注意返回值除了custom TargetSource(默认不会走这个分支)之外,都是null,因此不会阻断getBean的流程(见getBean分析)
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//缓存key
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//判断是否基础类型(Advice、Pointcut、Advisor、AopInfrastructureBean),基础类型不会代理
//shouldSkip判断是否应该跳过,这里面进行了切面的解析。
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//custom TargetSource 的处理, 没仔细研究
// 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.
...
return null;
}
skip方法
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
//找到候选的advisor,先找Advisor类型的,然后构建 aspectj 的。
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//切面不能对切面自己再做增强处理,应该跳过。
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
findCandidateAdvisors方法,注意这个方法被 AnnotationAwareAspectJAutoProxyCreator 重写了的:
protected List<Advisor> findCandidateAdvisors() {
//调用父类的方法找Advisor类型
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
//构建所有AspectJ的Advisors
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
先看下父类的 AbstractAdvisorAutoProxyCreator.findCandidateAdvisors 方法,它会去找容器中所有的Advisor类型,找到后通过getBean实例化:
public List<Advisor> findAdvisorBeans() {
//找到容器中所有的Advisor类型,并将名称缓存到cachedAdvisorBeanNames
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
//没有找到返回空列表
if (advisorNames.length == 0) {
return new ArrayList<>();
}
//有的话,getBean,然后加入到列表中返回。
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
...
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
...
}
}
}
return advisors;
}
对于示例中的AspectJ切面的方式, buildAspectJAdvisors 方法用来解析 AspectJ切面的:
public List<Advisor> buildAspectJAdvisors() {
//this.aspectBeanNames用来缓存容器中所有的aspectBeanNames。
List<String> aspectNames = this.aspectBeanNames;
//缓存为空,说明第一次触发该方法,进入解析。就算容器中没有aspectBean,在进行一次解析后, this.aspectBeanNames也不会为null。
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//查询出容器总所有的bean。
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
//遍历所有bean,如果是Aspect(可以简单理解为使用@Aspect注解的)bean,则构建对应的Advisor,并放到缓存中。
for (String beanName : beanNames) {
...
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//Aspect实例化的元信息工厂,封装了Aspect的元信息
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//构建Advisor。注意一个Aspect中可以定义多个通知或者切点(前置通知、后置通知),因此一个Aspect会构建出来多个Advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
//如果Aspect是单例,直接缓存对象
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
//否则缓存元信息工厂,后续可直接用工厂构建
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
....
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
//容器中压根没有Aspectj的bean,直接返回空列表
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
//如果有的话,遍历每个Aspectj,直接重缓存中获取(要么直接获取Advisor列表,要么获取到工厂,从工厂中获取)
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
//取缓存的成品
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
//取缓存的元信息工厂,然后创建新的Advisor的实例
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
现在来看看如何通过Aspect来解析构建出Advisor来的:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//从元信息工厂中获取Aspect的元信息
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验一波。
validate(aspectClass);
//这儿使用Decorator设计模式(装饰者),对元信息工厂包装一下,提供了缓存实例能力,这样就只需要实例化一次。
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
//遍历aspectClass的所有方法(包括父类或者接口的),注意要去除@PointCut注解的方法
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
//对方法上有切面相关的注解的(@Before\@After等),包装成 InstantiationModelAwarePointcutAdvisorImpl 这种类型的 Advisor 实例返回。
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
.....
return advisors;
}
getAdvisor方法:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//找到AspectJ的相关注解,封装为AspectJExpressionPointcut对象,注意会按照顺序找第一个出现的个人AspectJ注解【顺序为Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class】。
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//实例化 InstantiationModelAwarePointcutAdvisorImpl 返回
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
可以看到 AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation 方法核心作用就是找到容器中的所有切面,构建成Advisor放到缓存中。
创建代理对象
AnnotationAwareAspectJAutoProxyCreator 的另外一个重要的方法是 postProcessAfterInitialization, 它的调用时机位于bean实例化后(见getbean流程分析),它是真正创建代理对象的地方:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//如果必要的话,将对象包装成代理对象返回。IfNecessary这种命名方式在spring中也是比较常见的。
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary方法封装了包装代理对象的流程,其中核心为getAdvicesAndAdvisorsForBean方法(找到合适的增强器)和createProxy方法(创建代理对象)。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
...
//如果bean是不需要包装成代理对象的,直接返回,this.advisedBeans这个map,在前面的逻辑会对不需要代理的bean放到里面去。
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//再一次的对bean进行校验,是否需要包装为代理。不需要的放到this.advisedBeans中,标记为false。
//shouldSkip在前面已经分析过了,不同的是,因为已经对Aspectj解析过一遍了,再次调用时直接从缓存中获取。
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//需要代理的bean,则创建代理对象返回。
// Create proxy if we have advice.
//getAdvicesAndAdvisorsForBean 方法,找出满足当前bean的增强器(拦截器)。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//使用增强器对bean进行增强,创建出代理对象。
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;
}
getAdvicesAndAdvisorsForBean 方法会调用 findEligibleAdvisors 方法,其逻辑如下:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//找到所有的Advisor,这个方法前面已经调用过,直接从缓存中获取已经缓存的Advisor,advisor也可以叫做增强器。
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//从所有的增强器中,找出适配当前这个bean的。
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//留一个扩展点。
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//对增强器排序,这会影响拦截的处理流程(哪个增强器先执行,哪个后执行)
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply方法就是调用了 AopUtils.findAdvisorsThatCanApply 方法, 该方法会遍历所有增强器,然后和当前bean去做匹配(大概的匹配过程为是,获取到当前bean的所有方法,包括父类和接口,然后遍历方法去和增强器里面获取到的切点表达式进行匹配,篇幅问题,不展开),匹配上了将当前的增强器加入的适配的列表中。
现在有bean实例了,也找到合适的增强器,最后一步就是来创建代理对象了:
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//暴露代理对象到AopContext中(ThreadLocal),当然这里只是在MergedBeanDefinition设置一个属性,还暴露不了(因为代理对象还没创建)
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//代理工厂,代理对象由它来创建。
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//是否代理目标对象标记,这儿涉及到如果是代理目标对象的,底层使用cglib,否则底层使用JDK动态代理。
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//buildAdvisors,这方法中会加上公共的拦截器(默认为空),然后把传入的specificInterceptors包装成合适的Advisor返回。
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置代理对象的拦截器、目标源对象等
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
//又一个扩展点
customizeProxyFactory(proxyFactory);
//proxyFactory的其他配置
...
//创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
进入 ProxyFactory.getProxy方法,
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//getAopProxyFactory 默认使用的 DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
进入到 DefaultAopProxyFactory 的 createAopProxy方法,它会创建对应两种不同的AopProxy返回:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
....
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//返回JdkDynamicAopProxy这种AopProxy,它会使用JDK动态代理创建代理对象
return new JdkDynamicAopProxy(config);
}
//返回ObjenesisCglibAopProxy这种AopProxy,它会使用cglib创建代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
//返回JdkDynamicAopProxy这种AopProxy,它会使用JDK动态代理创建代理对象
return new JdkDynamicAopProxy(config);
}
}
以JdkDynamicAopProxy为例,它的getProxy方法:
public Object getProxy(@Nullable ClassLoader classLoader) {
...
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//熟悉的JDK动态代理代码,能传入this,是因为 JdkDynamicAopProxy 实现了 InvocationHandler 接口。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy的invoke方法中,包含了如何使用增强器对目标方法的增强逻辑,下一篇代理对象的调用在详细分析。
本篇文章详细分析了Spring AOP创建代理对象的原理,是如何找到@Aspectj标注的切面,又是如何解析成对应的Advisor,然后怎么从所有的Advisor中找到符合当前创建bean的,这些信息准备好了之后,最后是怎么创建代理对象的(分析了JDK动态代理方式,cglib的方式你可以自行分析,需要对cglib的库有所了解)