重磅推荐!美团内部开源Spring AOP源码小册,你确定不来看看

Hello,今天给各位童鞋们分享Spring AOP,赶紧拿出小本子记下来吧!

image.png

一、大话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的方式

动态代理

JDK 动态代理

CGLIB 代理

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

静态代理

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

二、动态AOP自定义标签

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

registerBeanDefinitionParser(“aspectj-autoproxy”, new AspectJAutoProxyBeanDefinitionParser());

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

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

注册或升级 AnnotationAwareAspectJAutoProxyCreator 注解解析器

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

1、JDK动态代理

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

2、CGLIB 代理

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

  • 目标对象使用动态代理方式总结:
  • 目标对象实现了接口,默认使用JDK代理;
  • 目标对象实现了接口可以强制使用CGLIB代理;
  • 目标对象没有实现接口,必须使用CGLIB代理。

JDK 动态代理只能针对实现了接口的类生成代理。

CGLIB代理 为指定类生成一个子类,并覆盖其中的方法,需要被增强的类或方法不能定义为 final
复制代码

三、创建AOP代理

AnnotationAwareAspectJAutoProxyCreator 类层次结构图

image.png
上一步实现了 AnnotationAwareAspectJAutoProxyCreator 的注册或升级,

它实现了 BeanPostProcessor 接口[实现该接口的后处理器,在Bean实例化时都会调用其postProcessAfterInitialization() 方法]

追踪代码可以发现,该方法由父类AbstractAutoProxyCreator 实现

追踪代码发现:

image.png
它主要包含的内容是:

1 . 获取增强方法 或者 增强器

2 . 对获取到的增强进行代理

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

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

根据方法找到如下实现:

protected List 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.获取所有增强器

image.png
2.寻找匹配的增强器

image.png
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类层次结构图

image.png
查看该解析类,发现 经由父类把 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 类层次结构图

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

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

    // 该后处理器 仅仅对 AspectJWeavingEnabler 类型的 bean 起作用 

	if (bean instanceof LoadTimeWeaverAware) { // 它的实现类只有 AspectJWeavingEnabler   处理器类

		LoadTimeWeaver ltw = this.loadTimeWeaver;//LoadTimeWeaver 实现类为:  DefaultContextLoadTimeWeaver

		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;

}
复制代码

DefaultContextLoadTimeWeaver 类层次结构图

image.png
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 类层次结构图

image.png
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 关联的是当前虚拟机实例,由它去处理静态织入(修改方法字节码)

最终会存在如下的引用关系

AspectJWeavingEnabler.loadTimeWeaver = DefaultContextLoadTimeWeaver.Instance();

DefaultContextLoadTimeWeaver.loadTimeWeaver = InstrumentationLoadTimeWeaver.Instance();

结语

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

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

好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享