SpringAOP 原理解析

时间:2022-04-18 13:01:14

什么是AOP?

1: 传统的OOP编程他的代码逻辑是一种自上向下, 而在这些自上而下的过程中会产生一些横切性的问题,比如说:日志信息,权限校验认证,事务等,

2: 这些横切性问题,往往与我们的主业务逻辑关系不大,并且散落在代码的各个地方,维护麻烦, AOP就是解决这个问题的,将主业务逻辑和这些横切性问题分离,达到解耦

如图所示:

SpringAOP 原理解析

SpringAop底层原理: 1:JDK代理, 2: cglib动态代理

对目标对象的方法进行前置处理,后置处理,这些处理的代码加到目标代码前后的过程叫: 织入, 那么 JDK代理和 cglib代理分别是什么时候织入呢? 编译期还是运行期? 如果是运行期,那么是在运行期spring容器初始化的时候织入?还是我们拿到这个目标对象的时候织入的(织入后将对象放入容器中)?

让我们一点一点深入了解

先说答案: 织入,实在运行期Spring容器初始化的时候织入的.它也属于Bean的生命周期一部分, 将生成的代理对象放入单例池中, spring容器初始化的时候, 会扫描xml,或者有@Component注解的类,根据这些类和他的注解(比如scope,islaze...)生成BeanDefinition,全部扫描完成的时候,BeanFactory就组建完成了,然后BeanFactoryPostProcessor,后置处理,在这个处理过程中,bean的属性注入,同时aop也生成了代理对象(放置了拦截器调用链),

使用AspectJ,步骤:

1: 添加依赖(aspectjweaver)

2: 配置类上添加注解:@EnableAspectJAutoProxy

3: 定义一个切面类(类上如果有这个注解@Aspect ,那么他就是一个切面类),并交给spring容器管理,@Component

4: 声明一个切点, 切面类中的某个方法上如果有这个注解(@PointCut("excution(* com.boo.service..(..))")), 关于切点表达式可以自己看官方文档

5: 定义通知: 如果一个方法上有注解@AfterReturning("com.aop.config.UserAspectJ.pointCut()"), 说明这个是后置通知, 括号中是指向当前切面类的切点

6: 启动容器,测试

那么在spring源码中是如何实现AOP的? 几个关键的类

https://www.cnblogs.com/51life/p/9243021.html , 这里引用别人的笔记..感谢他

1: 查看源码中Bean初始化过程中,是如何解析xml 中的aop:aspectj-autoproxy/,

AbstractApplicationContext类: 的refresh()方法中的obtainFreshBeanFactory(); 作用:初始化容器, 解析xml中的标签(包括 pointCut标签,ADVISOR标签,ASPECT标签...)将Bean转换为BeanDefiniton

2: refresh()方法中的registerBeanPostProcessors(beanFactory); 作用: 注册各种各样的Bean后置处理器,这里就包括了AspectJAwareAdvisorAutoProxyCreator(这个是aop后置处理器)

3: AbstractAutowireCapableBeanFactory类的initializeBean()方法: 作用是实例化Bean,并给Bean注入属性(这个方法中可以看到 各种 ...Aware...类的回调自身赋值属性 ), 这里就包括了目标对象的实例化和注入属性,目标对象生成之后,最后一步是AspectJAwareAdvisorAutoProxyCreator(这个是aop后置处理器)开始处理目标对象,AbstractAutoProxyCreator类中的 createProxy()方法,进而生成代理对象, 这里会看到有二种代理方式: JDK代理 cglib代理, 将生成的代理对象放入单例池

4: 代理对象生成之后,那么"织入"这个是如何实现呢? 拦截器实现. AbstractAutoProxyCreator类中的 createProxy()方法中不仅仅生成了代理对象, 生成代理对象的时候同时也将 拦截器调用链放置到代理对象中了, Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 这个this,就是调用自身的invoke()方法, 这个方法中可以看到 retVal = invocation.proceed();这个是AOP的核心,如何对目标进行增强的

1: AbstractApplicationContext类: 的refresh()----obtainFreshBeanFactory();---loadBeanDefinitions(beanFactory);---XmlWebApplicationCotnext类的loadBeanDefinitions()--loadBeanDefinitions(beanDefinitionReader);----reader.loadBeanDefinitions(configLocation);-----int count = loadBeanDefinitions(resources);----XmlBeanDefinitionReader类的loadBeanDefinitions----doLoadBeanDefinitions(inputSource, encodedResource.getResource());---documentReader.registerBeanDefinitions(doc, createReaderContext(resource));---parseBeanDefinitions(root, this.delegate);-----delegate.parseCustomElement(ele);(这个是解析其他的标签,而非默认的(beans,alias..))----handler.parse---ConfigBeanDefinitionParser类的parseAspect, 这里就可以看到解析POINTCUT 标签,ASPECT标签, 转换为BeanDefinition然后存入list中

2: refresh()----registerBeanPostProcessors(beanFactory); 这个方法的逻辑是,先获取所有的后置处理器,然后分类存储, 然后创建对应的处理器,这里就包括了AspectJAwareAdvisorAutoProxyCreator

3: AbstractAutowireCapableBeanFactory类的initializeBean()----applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);-----AbstractAutoProxyCreator类wrapIfNecessary(bean, beanName, cacheKey);---createProxy---proxyFactory.getProxy(getProxyClassLoader());----这里会看到二个实现类 CglibAopProxy JdkDynamicAopProxy

4: 织入的实现: AbstractAutoProxyCreator类中createProxy()----invoke()--List