Hello,今天给各位童鞋们分享Spring AOP,赶紧拿出小本子记下来吧!
一、大话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 定位到如下代码
上述代码主要实现如下功能:
注册或升级 AnnotationAwareAspectJAutoProxyCreator 注解解析器
处理 proxy-target-class 和 expose-proxy 属性
1、JDK动态代理
其代理对象必须实现某个接口,它通过在运行期间,创建接口的实现类来完成对目标对象的代理。
2、CGLIB 代理
它在运行期间生成的代理对象是针对目标类型拓展的子类。
- 目标对象使用动态代理方式总结:
- 目标对象实现了接口,默认使用JDK代理;
- 目标对象实现了接口可以强制使用CGLIB代理;
- 目标对象没有实现接口,必须使用CGLIB代理。
JDK 动态代理只能针对实现了接口的类生成代理。
CGLIB代理 为指定类生成一个子类,并覆盖其中的方法,需要被增强的类或方法不能定义为 final
复制代码
三、创建AOP代理
AnnotationAwareAspectJAutoProxyCreator 类层次结构图
上一步实现了 AnnotationAwareAspectJAutoProxyCreator 的注册或升级,
它实现了 BeanPostProcessor 接口[实现该接口的后处理器,在Bean实例化时都会调用其postProcessAfterInitialization() 方法]
追踪代码可以发现,该方法由父类AbstractAutoProxyCreator 实现
追踪代码发现:
它主要包含的内容是:
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.获取所有增强器
2.寻找匹配的增强器
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 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 类层次结构图
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 关联的是当前虚拟机实例,由它去处理静态织入(修改方法字节码)
最终会存在如下的引用关系
AspectJWeavingEnabler.loadTimeWeaver = DefaultContextLoadTimeWeaver.Instance();
DefaultContextLoadTimeWeaver.loadTimeWeaver = InstrumentationLoadTimeWeaver.Instance();
结语
-
OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
-
使用”横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们