spring源码系列:Aop基础编程以及Spring Aop基于Aspect注解方式源码分析

AOP编程中的基本概念

  1. 连接点: 程序执行某个特定位置,如类的初始化前后,某个方法调用前后,方法报出异常后,一个类或者一段代码拥有一些边界性质的特定点。Spring仅支持方法的连接点
  2. 切点: 每个程序都拥有多个连接点。AOP通过切点定位连接点,一个切点可以对应多个连接点。
  3. 增强: 增强是一段代码。是织入到目标类的连接点上的一段代码。
  4. 目标对象: 增强逻辑的织入目标类
  5. 引介: 引介是特殊的增强,他为类添加一些属性和方法
  6. 织入: 将增强添加到具体目标对象的连接点的过程
  7. 切面: 切面是由切点和增强组成

Spring中的概念

  • advisor: 封装了SpringAop的切点和通知(类似为切面) 后面我们把advisor结尾的类称为切面类
  • advice: 通知,也就是增强。后面我们把spring中以advice结尾的类称为增强类
  • creator: 相当于织入(只不过spring是通过动态代理织入增强的) 为了方便称呼我们后面把creator结尾的类成为织入类

核心类

advisorCreator自动织入类:

  • BeanNameAutoProxyCreator: 根据指定的名称创建代理对象,通过设置advisor,可以对指定的beanName进行代理。支持模糊
  • AbstractAdvisorAutoProxyCreator: 扫描所有的advisor的实现类。动态匹配每一个类,判断是否可以被代理。默认的实现类是DefaultAdvisorAutoProxyCreator
  • AspectJAwareAdvisorAutoProxyCreator: AspectJ的实现方式,spring最常用的实现方式。其子类(AnnotationAwareAspectJAutoProxyCreator)是默认的支持方式,会扫描@Aspect注解的类,生产对应的切面。

advisor核心类(都集成Advisor接口)

  • StaticMethodMatcherPointcut: 静态方法切面,抽象类。定义了一个classFilter,通过重写getClassFilter()方法来指定切面规则。另外实现了StaticMethodMatcher接口,通过重写matches来指定方法匹配规则
  • StaticMethodMatcherPointcutAdvisor: 静态方法匹配切面,扩展了排序方法。
  • NameMatchMethodPointcut: 名称匹配切面,通过指定方法集合变量mappedNames,模糊匹配。
  • NameMatchMethodPointcutAdvisor: 方法名称切面,内部封装了NameMatchMethodPointcut,通过设置方法名称模糊匹配规则和通知来实现切面功能
  • DefaultPointcutAdvisor: 默认的切面类
  • RegexpMethodPointcutAdvisor: 用于支持正则表达式的切面类,可支持函多个正则表达式
  • NameMatchMethodPointcutAdvisor: 方法名称切面
  • InstantiationModelAwarePointcutAdvisorImpl: 自动封装的切面实现。在自动织入的时候会默认会把AspectJ注解默认包装改该类。比较常用的切面类

advice增强核心类

  • AspectJMethodBeforeAdvice: 前置增强(@Before标注的方法会被解析成该通知)
  • AspectJAfterReturningAdvice: 后置增强(@AfterReturning 标注的方法会被解析成该通知)
  • AspectJAroundAdvice: 环绕增强(@Around标注的方法会被解析成该通知)
  • AspectJAfterAdvice: 返回增强(@After 标注的方法会被解析成该通知)忽略异常

SpringAop基于AspectJ注解方式

目标对象

@Component
public class TargetA {

  public void sayHello(){
    System.out.println("sayHello");
  }
}

增强

@Component
@Aspect
public class ProxyA {

  @Pointcut("execution(* org.springframework.apo..*.*(..))")
  public void point(){
  }

  @Before("point()")
  public void before(){
    System.out.println("begin say..");
  }

  @After("point()")
  public void after(){
    System.out.println("after say ...");
  }
}

启动类

@ComponentScan("org.springframework.apo")
@EnableAspectJAutoProxy
public class App {
  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
    TargetA bean = applicationContext.getBean(TargetA.class);
    bean.sayHello();
  }
}

可以看到在spring中我们只需要定义增强 其他的不需要我们关心。 spring的creator会帮我织入到目标类。上面的流程最关键的两点 其一是AspectJ连接点表达式比较关键 其二是在启动类上加@EnableAspectAutoProxy注解(springboot引入了spring-boot-starter-aop就不需要再手动Enabled)。下面我们从注解入手看一下 spring织入的整个流程。

Spring AOP源码分析

启动注解EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;

}

我们看到上述代码中使用@Import标签向spring容器中导入了一个AspectJAutoProxyRegistrar。继续跟进AspectJAutoProxyRegistrar

@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          //向IOC容器中注入AnnotationAwareAspectJAutoProxyCreator 
		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);
			}
		}
	}

上面代码其实主要是向容器中加了AnnotationAwareAspectJAutoProxyCreator 这个织入类。并根据我们的配置(注解中有两个属性 后续会讲解)。到这这个注解的使命就完成了。那为什么像springIOC容器注入了一个AnnotationAwareAspectJAutoProxyCreator 就能实现织入的能力呢?下面我们从这个类入手了解一下spring的整个织入流程。

类的继承关系

AnnotationAwareAspectJAutProxyCreator继承关系

在看spring源码的时候我们可以发现 spring框架中大量运用了模板方法模式。所以只要出现Abstract开头的类 我们就应该好好的去看一下。分析这一部分的源码我们就从第第一个抽象类入手AbstractAutoProxyCreator。
看一下初始化过程

父类初始化AbstractAutoProxyCreator

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
   @Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}
	
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}
}

子类初始化

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
 //这个方法是在bean初始化之前调用 在spring启动期间会把BeanFactory注入进来 是一个初始化方法。
   @Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		if (this.aspectJAdvisorFactory == null) {
		//ReflectiveAspectJAdvisorFactory是一个支持AspectJ注解的类。可以解析AspectJ注解包装成Advisor。简单的理解是对AspectJ的语法的支持。
			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
		}
		//这里是对ReflectiveAspectJAdvisorFactory的包装 内部真正解析AspectJ注解的是ReflectiveAspectJAdvisorFactory类。
		this.aspectJAdvisorsBuilder =
				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
	}
}

可以发现它实现了SmartInstantiationAwareBeanPostProcessor 。这个接口是springIOC容器的扩展接口其最顶层的父接口是BeanPostProcessor。在springIOC容器启动和 bean的创建 初始化前后调用。如果对这一块比较模糊可以去看一下BeanFactoryPostProcessor和BeanPostProcessor这两个父接口衍生出来的几个接口的注释。里面对于调用点的注释还挺清楚。我们这里就不做过多解释了。

下面我们把这个类中我们需要用的方法复制出来

     //这个方法是InstantiationAwareBeanPostProcessor接口中的方法 是在bean实例化之前被调用
     @Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);
		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
		    //advisedBeans用于存储不能被代理的bean  如果当前bean出现在集合中立马返回
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			//如果当前类继承 Advice,Pointcut,Advisor,AopInfrastructureBean等这些类也不能被
			//代理
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		//得到目标源 这是一次尝试 因为如果我们设置customTargetSourceCreators 这个属性 这个时候就
		//会获取我们设置的TargetSource对象 如果没设置就跳过了这个方法。 下面的代理过程我们暂且先不管
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
			    //如果找到确实设置了TargetSource 就加入到缓存集合
				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;
	}

下面我们看一下shouldSkip这个方法 子类的实现

  @Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// 从bean工厂中查找所有的advisor 如果当前bean的名字在当前advisor的列表中 则跳过不需要代理
		//暂时不展开
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

上面我们分析了postProcessBeforeInstantiation方法 如果设置自定义的TargetSourceCreator 就只做了一件事件 找到所有的增强并封装成切面

//这个方法BeanPostProcessor中的方法 在bean初始化(初始化方法)之后调用。
    @Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			    //重点是这里 进入这个方法
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
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;
		}
		//前面都是判断  直接来到这一行代码 我们暂时不展开  大概的意思是从我们所有的切面中筛选符合当前bean的切面
		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;
	}

到目前为止 如果我们不展开getAdvicesAndAdvisorsForBean 方法和createProxy方法 其实整个过程已经结束了。


最后我们着重分析一下advisor的创建过程和代理类的创建过程

  1. advisor创建 getAdvicesAndAdvisorsForBean这个方法是一个抽象方法 是并且是AbstractAutoProxyCreator唯一的一个抽象方法 我们直接进入子类(AbstractAdvisorAutoProxyCreator)的实现

   protected Object[] getAdvicesAndAdvisorsForBean(
   		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   	//这里继续调用查找Advisor的方法	
   	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   	if (advisors.isEmpty()) {
   		return DO_NOT_PROXY;
   	}
   	return advisors.toArray();
   }

继续跟进findEligibleAdvisors 当前所在AbstractAdvisorAutoProxyCreator类

  	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  	    //这个方法被子类重写就是查找被AspectJ语法修饰的切面
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//找出所有切面应用在当前实例上面的
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//扩展方法  子类实现的时候像 集合中加入了ExposeInvocationInterceptor
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

进入子类的findCandidateAdvisors方法

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// 先调用父类的方法获取容器中所有实现Advisor的子类的实例
		List<Advisor> advisors = super.findCandidateAdvisors();
		if (this.aspectJAdvisorsBuilder != null) {
		//然后加入所有AspectJ注解修饰的切面
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

继续展开this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 这个方法是查找的核心 代码有点多

public List<Advisor> buildAspectJAdvisors() {
//aspectBeanNames这个是缓存的所有 有AspectJ注解的实例  第一次是null
		List<String> aspectNames = this.aspectBeanNames;
		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
         //这里就是找到所有的bean 因为传的类型是Object 所以所有的实例的名字都会查找出来 					
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						if (!isEligibleBean(beanName)) {
							continue;
						}
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						//这里判断当前类型是否有AspectJ注解
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
     //这里找到当前实例的Advisor 这里不作展开了 就是通过反射拿到对应的方法封装成InstantiationModelAwarePointcutAdvisorImpl的过程										
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								//这里缓存分为单例和原型的方式缓存
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								//然后将本次解析结果加入集合
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}

到此我们的解析Advisor流程就结束了


下面我们在看一下代理的创建

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区别于ProxyFactoryBean 关于ProxyFactoryBean后面会介绍
		ProxyFactory proxyFactory = new ProxyFactory();
//设置一些ProxyFactory的属性例如proxyTargetClass,exposeProxy 因为 ProxyFactory和AbstractAutoProxyCreator都继承自ProxyConfig		
//下面都是对ProxyFactory的设置
		proxyFactory.copyFrom(this);
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//设置切面
		proxyFactory.addAdvisors(advisors);
		//设置代理源
		proxyFactory.setTargetSource(targetSource);
		//这个是扩展方法 留个子类实现可以对ProxyFactory自定义。
		//例如我们可以自定义一种织入策略  实现AbstractAutoProxyCreator 然后重写该方法 去自定义ProxyFactory
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		//这里是创建代理的逻辑
		return proxyFactory.getProxy(getProxyClassLoader());
	}

下面进入getProxy中 下面这个方法就是根据代理类是否有接口去创建不同的AopProxy

	@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);
		}
	}

如果proxy-target-class 设置为true 除非被代理的类是一个接口 一般情况下是要使用CGLIB代理的。springboot环境下默认就是true。

好了到这里 我们把基本的流程叙述了一遍。这一块的代码太多 不可能很详细 读者可以下去自行翻阅。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值