Spring源码分析之AOP

AOP是什么

面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计剖面导向程序设计),是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰。

怎么在Spring里使用AOP

Spring里,AOP通过EnableAspectJAutoProxy注解开启。默认情况下,Spring会通过AopAutoConfiguration自动引入这个注解

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
   
   

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {
   
   

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		static class JdkDynamicAutoProxyConfiguration {
   
   

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {
   
   

		}

	}
}

可以看到,如果我们不主动设置spring.aop.auto=false。那么Spring默认会启用AOP。接下来,我们可以通过在类上标注Aspect即可使用AOP

package org.example.aspect;

@Aspect
@Component
public class SampleAspect {
   
   

    @Pointcut("execution(* org.example.xxx.*.*(..))")
    private void executionPointcut() {
   
   

    }

    @After(value = "executionPointcut()")
    public void doAfter() {
   
   
        
    }
}

源码分析

1. AOP初始化

1.1 初始化AspectJAutoProxyRegistrar

EnableAspectJAutoProxy通过Import注解引入了AspectJAutoProxyRegistrar

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   
   
}

AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrarSpring在初始化AopAutoConfiguration时把所有通过Import注解引入的ImportBeanDefinitionRegistrar实现类拿出来进行初始化,并调用其registerBeanDefinitions函数

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   
   

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
   

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

}

1.2 初始化AnnotationAwareAspectJAutoProxyCreator

AspectJAutoProxyRegistrar 则在registerBeanDefinitions注册了一个AnnotationAwareAspectJAutoProxyCreatorBeanDefinition

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
   
   

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessorSpring会在初始化普通Bean之前初始化所有BeanPostProcessor

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
   
   

		public void refresh() throws BeansException, IllegalStateException {
   
   
					// 初始化BeanProcessor来拦截Bean的创建
					registerBeanPostProcessors(beanFactory);
	
					// 初始化所有剩下的非懒加载的Bean,比如我们写的Service
					finishBeanFactoryInitialization(beanFactory);
		}
}

1.3 初始化切面方法跟切点

另外,AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessorSpring 会在Bean创建时调用其postProcessBeforeInstantiation方法对Bean进行处理。

在第一次调用该方法时,AnnotationAwareAspectJAutoProxyCreator会初始化切面

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
   
   
	
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   
   
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
   
   
			//判断当前BeanName对应的Bean是否应该被代理
			//并将判断结果保存下来,避免后续的后处理方法重复计算
			//在第一次判断时,会在shouldSkip里扫描所有Bean进行切面初始化
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
   
   
				this.advisedBeans.put
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值