Spring源码之-AOP




PS * 文中代码均为伪代码,本文基于spring 5.0 ,如有谬误,感谢指正!!!


一、大话AOP

1.AOP的概念

  • AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

  • AOP技术利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

从概念上来说很清晰,仅对入门小白来说存在一些门槛。

总结来说,AOP 提供的功能是 减少重复代码,通过切面来实现一些重复的逻辑代码。

2.必要的准备工作

个人认为阅读spring源码前务必请读一下常用设计模式,比如AOP 中最重要的设计模式:代理模式。

什么是代理模式?

  • 代理模式为另一个对象提供一个替身或者占位符,以控制对这个对象的访问。也可使是视作代理对象让客户代码于实际对象解耦。使用代理模式创建代表对象,让代表对象控制对某对象的访问,被代理的对象可以是远程的对象(运行在不同JVM上,通过RMI实现)、创建开销大的对象(虚拟代理模式)或者需要安全控制的对象(保护代理模式)。

可以简单认为,代理模式把<实际需要访问的对象>封装到了,一个<与实际对象实现了相同接口的对象>中,这个用于封装实际对象的外层对象,称之为 <代理对象>。对<被代理对象>的访问,全部通过<代理对象>进行。

-- 助记定义
<实际需要访问的对象>   即  被代理对象。
<与实际对象实现了相同接口的对象>  即  代理对象。

3.大话AOP

那么AOP 具体是什么呢?

对没有接触过AOP的,人来说,你跟他讲切面、切点、织入,这是非常抽象的。

用最直白的话来说:AOP 实现的逻辑就是为原对象生成<代理对象>,处理<代理对象> 最终实现增强。[ JDK动态代理: InvocationHandler.invoke()、CGLIB代理: MethodInterceptor.intercept() ]

实现AOP的方式

  1. 动态代理
  • JDK 动态代理

  • CGLIB 代理

    动态代理,在运行时动态织入增强,所以会对运行性能造成损耗。

  1. 静态代理
    在虚拟机加载字节码文件的时候,将增强内容织入到方法的字节码中,它提供了更细粒度的控制,对性能影响较小。

二、动态AOP自定义标签

全局搜索 AOP 配置项很容易定位到如下代码:

registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

最终接口方法parse 定位到如下代码

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {

		// 是否已经存在:自动代理创建器,已存在判断优先级,不存在创建默认类型
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		//  处理 proxy-target-class 和 expose-proxy 属性
		//  proxy-target-class  决定使用的代理类型:JDK动态代理,应用场景更加多元,通过实现接口代理,确定是性能不够强悍;CGLIB代理,通过继承目标类实现拓展,操作低层字节码,性能强悍。
		//  expose-proxy :  目标对象内部的自我调用将无法实施切面中的增强,利用 expose-proxy 属性可以解决这个问题
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		//  注册组件并通知,便于监听器做进一步的处理
		//  beanDefinition 代表的是 AnnotationAwareAspectJAutoProxyCreator的类定义
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

上述代码主要实现如下功能:

  • 注册或升级 AnnotationAwareAspectJAutoProxyCreator 注解解析器

  • 处理 proxy-target-class 和 expose-proxy 属性

1、JDK动态代理

其代理对象必须实现某个接口,它通过在运行期间,创建接口的实现类来完成对目标对象的代理。

2、CGLIB 代理

它在运行期间生成的代理对象是针对目标类型拓展的子类。


目标对象使用动态代理方式总结:
  • 目标对象实现了接口,默认使用JDK代理;

  • 目标对象实现了接口可以强制使用CGLIB代理;

  • 目标对象没有实现接口,必须使用CGLIB代理。

	JDK 动态代理只能针对实现了接口的类生成代理。
	CGLIB代理 为指定类生成一个子类,并覆盖其中的方法,需要被增强的类或方法不能定义为 final

三、创建AOP代理

AnnotationAwareAspectJAutoProxyCreator 类层次结构图
pic1

上一步实现了 AnnotationAwareAspectJAutoProxyCreator 的注册或升级,
它实现了 BeanPostProcessor 接口[实现该接口的后处理器,在Bean实例化时都会调用其postProcessAfterInitialization() 方法]
追踪代码可以发现,该方法由父类AbstractAutoProxyCreator 实现

追踪代码发现:

// 要么返回bean 要么返回被代理后的bean-proxy
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// advisedBeans : 需要被增强的
		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;
		}

		// Create proxy if we have advice.
		// 获取所有需要被增强的方法?
		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;
	}

它主要包含的内容是:

1 . 获取增强方法 或者 增强器
2 . 对获取到的增强进行代理

本节剩下的内容都是在讲述他们

关注获取增强方法的 getAdvicesAndAdvisorsForBean 方法,由 父类 AbstractAdvisorAutoProxyCreator 实现

根据方法找到如下实现:


protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// AnnotationAwareAspectJAutoProxyCreator 类覆盖了该方法 
		List<Advisor> candidateAdvisors = findCandidateAdvisors();// 获取所有的增强 (所有  拦截||切点???)
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 寻找适用于当前 Bean 的增强 
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

1.获取所有增强器

public List<Advisor> findAdvisorBeans() {
		// 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!
			// 获取 beanFactory 中的所有 注册的 beanName &&  声明为  @AspectJ
			advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);
			this.cachedAdvisorBeanNames = advisorNames;
		}
		if (advisorNames.length == 0) {
			return new ArrayList<>();
		}
		
		List<Advisor> advisors = new ArrayList<>();// 记录增强 ??
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {// 模板方法模式思想-钩子函数 : 校验 该bean 是否合格????
				if (this.beanFactory.isCurrentlyInCreation(name)) { // 新 创建 ??
					if (logger.isDebugEnabled()) {
						logger.debug("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					// 提取 增强并缓存 
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
			}
		}
		return advisors;
	}

2.寻找匹配的增强器

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		// 处理引介增强
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);// 适合 ?? 拦截条件成立??
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			// 跳过引介增强(已处理)
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			// 普通 bean 处理
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

3.创建代理

最后回到 wrapIfNecessary 方法,获取到增强方法后,将调用 createProxy 创建代理

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);//  添加代理接口
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);//  拦截器封装为 Advisor 
		proxyFactory.addAdvisors(advisors);//  加入增强器 
		proxyFactory.setTargetSource(targetSource);//  设置要代理的类
		customizeProxyFactory(proxyFactory);//  定制化内容,钩子函数

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());//  获取代理
	}

最终指向 createAopProxy().getProxy();

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

查看代码很容易看到,ObjenesisCglibAopProxy 和 JdkDynamicAopProxy 都实现了接口 AopProxy

四、创建AOP静态代理

1.自定义标签

全局搜索 AOP静态织入 配置项:load-time-weaver 可以发现如下的代码入口

registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());

LoadTimeWeaverBeanDefinitionParser类层次结构图
在这里插入图片描述

查看该解析类,发现 经由父类把 parse 方法 转为了 doParse 方法

    // 以标签为标志,进行相关  《处理类》 的注册 
	// parse 到 doParse的转化:  parse()   ->  parseInternal()  ->  doParse()
	// 解析(×)  注册工具类(√) 
	// 解析load-time-weaver 标签会产生一个 beanName为 loadTimeWerver 的 bean  class=org.springframework.context.weaving.DefaultContextLoadTimeWeaver
	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

		// 检查AspectJ 功能是否可用(load-time-weaver:-> aspectj-weaving<on off autodetect>)  {default=autodetect 检查 META-INF/aop.xml 是否存在}
		if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {// aspectj-weaving
			if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) {//  org.springframework.context.config.internalAspectJWeavingEnabler
				RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);// org.springframework.context.weaving.AspectJWeavingEnabler
				parserContext.registerBeanComponent(
						// org.springframework.context.config.internalAspectJWeavingEnabler
						new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME)); // 封装 <处理类> AspectJWeavingEnabler 并注册   注册到容器中??
				// BeanDefinitionHolder 
			}

			if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {// 检查是否已经注册成功
				new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
			}
		}
	}

经过上述步骤,解析器 已经被封装为BeanDefinition并注册到了容器中,那么要怎样使用它呢,
查看AbstractApplicationContext 类,如下为织入前的准备工作,将相关的后处理器链注入

/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		/*
		* 其它无关代码不再列出
		*/
		
		//  增加 对 AspectJ 的支持  AOP  相关后处理器  load-time-weaving  静态织入 
		// 容器中查找 beanName为 loadTimeWeaver 的 类,如果存在即可说明 静态织入开关存在
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {// loadTimeWeaver 
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// 注册 aop 相关后处理器
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
		/*
        * 其它无关代码不再列出
        */
	}

2.织入

LoadTimeWeaverAwareProcessor 类层次结构图

在这里插入图片描述

既然有后置处理器接口,那就在原类中找如下两个方法,自然就能找到静态织入的执行逻辑了。

初始化前会调用 后处理器 LoadTimeWeaverAwareProcessor 的 postProcessBeforeInitialization() 方法

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	    // 该后处理器 仅仅对 AspectJWeavingEnabler 类型的 bean 起作用 
		if (bean instanceof LoadTimeWeaverAware) { // 它的实现类只有 AspectJWeavingEnabler   处理器类
            // LoadTimeWeaver 实现类为:DefaultContextLoadTimeWeaver 
            // 至于为什么是它,可以全局搜索,静态织入开关的标签解析器: 
			// oad-time-weaver  ->  LoadTimeWeaverBeanDefinitionParser  ->  DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME
			LoadTimeWeaver ltw = this.loadTimeWeaver;
			if (ltw == null) {
				// 最终获得一个 DefaultContextLoadTimeWeaver 类型 bean  
				ltw = this.beanFactory.getBean(ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
			}
			//  AspectJWeavingEnabler 持有 loadTimeWeaver 
			((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);// 注入到   AspectJWeavingEnabler 的 loadTimeWeaver 属性
		}
		return bean;
	}

首先是负责静态织入 (AspectJWeavingEnabler)bean 的类图,是不是又看到了老熟人:BeanFactoryPostProcessor

是不是又看到了老熟人:BeanFactoryPostProcessor 这不是工厂的后置处理器么?
那么再看 AspectJWeavingEnabler 的 postProcessBeanFactory() 方法不就是后续的路子了么?

  • 被注入到 bean 中的 loadTimeWeaver (DefaultContextLoadTimeWeaver) 将是后续的关键

DefaultContextLoadTimeWeaver 类层次结构图
在这里插入图片描述

DefaultContextLoadTimeWeaver 实现了接口 BeanClassLoaderAware ,那么它的 setBeanClassLoader() 方法将会在初始化的时候被调用,
从方法中可以看到,DefaultContextLoadTimeWeaver 类型的 bean 的loadTimeWeaver 属性设置为:InstrumentationLoadTimeWeaver 类型的bean,
而最终实现静态AOP织入(修改方法字节码) 的就是它(InstrumentationLoadTimeWeaver)
InstrumentationLoadTimeWeaver

@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
		if (serverSpecificLoadTimeWeaver != null) {
			this.loadTimeWeaver = serverSpecificLoadTimeWeaver;
		}
		else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {// 检查当前虚拟机中的 Instrumentation 实例是否可用  
			this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
		}
		else {
			this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
            if (logger.isInfoEnabled()) {
                logger.info("Using a reflective load-time weaver for class loader: " +
                        this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
            }
		}
	}

最后,AspectJWeavingEnabler 实现了 BeanFactoryPostProcessor 接口,那么在所有bean解析结束后会调用其:
postProcessBeanFactory()方法 -> enableAspectJWeaving()

AspectJWeavingEnabler 类层次结构图
在这里插入图片描述

public static void enableAspectJWeaving(
			@Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) {

		if (weaverToUse == null) {
			if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {// 当前虚拟机的 Instrumentation 是否可用 
				weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
			}
			else {
				throw new IllegalStateException("No LoadTimeWeaver available");
			}
		}
		weaverToUse.addTransformer(
				new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
	}

最终,看到了实现的代码:

/**
	 * ClassFileTransformer decorator that suppresses processing of AspectJ
	 * classes in order to avoid potential LinkageErrors.
	 * @see org.springframework.context.annotation.LoadTimeWeavingConfiguration
	 */
	private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {

		private final ClassFileTransformer delegate;

		public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {
			this.delegate = delegate;
		}

		@Override
		public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
				ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

			if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
				return classfileBuffer;
			}
			// 具体逻辑委托给代理 
			return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
		}
	}
  • LoadTimeWeaverAwareProcessor.postProcessBeforeInitialization() 方法将 DefaultContextLoadTimeWeaver 注册到 AspectJWeavingEnabler 的 loadTimeWeaver 属性中
  • DefaultContextLoadTimeWeaver 实现了接口 BeanClassLoaderAware(实现了该接口的 bean 在 AbstractAutowireCapableBeanFactory.invokeAwareMethods 调用时,
    会去调用:BeanClassLoaderAware.setBeanClassLoader ,该方法逻辑内会把代表当前虚拟机的 InstrumentationLoadTimeWeaver实例,注册到 DefaultContextLoadTimeWeaver 的 loadTimeWeaver属性)

Instrumentation 关联的是当前虚拟机实例,由它去处理静态织入(修改方法字节码),前边通过AOP 定义的,满足条件的切面,将以字节码的形式注入到目标bean中

最终会存在如下的引用关系
AspectJWeavingEnabler.loadTimeWeaver = DefaultContextLoadTimeWeaver.Instance();
DefaultContextLoadTimeWeaver.loadTimeWeaver = InstrumentationLoadTimeWeaver.Instance();

结语

  • OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

  • 使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

引用文章
[1] https://www.cnblogs.com/hongwz/p/5764917.html

posted @ 2021-06-19 17:19  bokerr  阅读(60)  评论(0编辑  收藏  举报