Spring基于注解开发的注解使用之AOP(部分源代码分析)
AOP底层实现动态代理
1、导入spring-aop包依赖
<!--aopV1-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency>
<!--aopV2-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
2、在配置类加入注解
@EnableAspectJAutoProxy//启用AOP切面(开启注解版的AOP功能)
3、@Aspect
在切面类上加入@Aspect表示这是一个切面
4、切面配置
spring官方文档(https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-introduction-defn)
-
/*
-
标识这个方法是个前置通知, 切点表达式表示执行任意类的任意方法.
-
第一个 * 代表匹配任意修饰符及任意返回值,
-
第二个 * 代表任意类的对象,
-
第三个 * 代表任意方法,
-
参数列表中的 .. 匹配任意数量的参数
-
*/
-
The execution of any public method:
execution(public * *(..))
-
The execution of any method with a name that begins with
set
:execution(* set*(..))
-
The execution of any method defined by the
AccountService
interface:execution(* com.xyz.service.AccountService.*(..))
-
The execution of any method defined in the
service
package:execution(* com.xyz.service.*.*(..))
-
The execution of any method defined in the service package or one of its sub-packages:
execution(* com.xyz.service..*.*(..))
-
Any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
-
Any join point (method execution only in Spring AOP) within the service package or one of its sub-packages:
within(com.xyz.service..*)
-
Any join point (method execution only in Spring AOP) where the proxy implements the
AccountService
interface:this(com.xyz.service.AccountService)
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
@AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
指定返回参数
@AfterReturning(
pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
制定异常(返回)
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
获取输出参数
//先定义切点(Pointcut)
@Pointcut("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account) {}
//使用切点
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
使用
@Configuration
@ComponentScan("com.test2")
@EnableAspectJAutoProxy
public class Config1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext content = new AnnotationConfigApplicationContext(Config1.class);
System.out.println("********BeanDefinition*********");
Arrays.stream(content.getBeanDefinitionNames()).forEach(val -> {
System.out.println(val);
});
System.out.println("********BeanDefinition*********");
System.out.println("############spring--容器启动完成############");
TestService testService = content.getBean(TestService.class);
testService.addUser();
}
}
//控制台输出
LogAspect--around-before
LogAspect--before
com.test2.bean.TestService执行addUser动作
LogAspect--afterReturning返回结果:添加成功
LogAspect--after
LogAspect--around-after返回值:添加成功
Aspect类定义
package com.test2.bean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* Created by user on 2021/1/18.
*/
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.test2.bean.TestService.*(..))")
public void pointCut() {
}
//JoinPoint必须是方法的第一个参数,否则spring会无法识别。具体查看spring源码分析
@Before("execution(public String com.test2.bean.TestService.addUser())")
public void before(JoinPoint point) {
System.out.println(point.getSignature().getName());//方法
System.out.println(point.getArgs());//参数
System.out.println("LogAspect--before");
}
@After(value = "pointCut()")
public void after() {
System.out.println("LogAspect--after");
}
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(Object result) {
System.out.println("LogAspect--afterReturning" + "返回结果:" + result);
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void afterThrowing(Exception exception) {
System.out.println("LogAspect--AfterThrowing" + exception.getMessage());
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("LogAspect--around-before");
long beginTime = System.currentTimeMillis();
Object result = point.proceed();//实际方法执行
long time = System.currentTimeMillis() - beginTime;
System.out.println("LogAspect--around-after" + "返回值:" + result);
return result;
}
}
@Service
public class TestService {
public String addUser() {
System.out.println(this.getClass().getName() + "执行addUser动作");
int i = 1/0;//手动抛出异常【如果手动抛出异常时,afterThrowing会被执行,且能够接受到具体的异常信息】
return "添加成功";
}
}
AOP原理
@EnableAspectJAutoProxy
//加入AOP后,才开始起作用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//给容器导入某个Bean
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
导入组件(AspectJAutoProxyRegistrar)
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
}
给Spring容器导入Bean---AspectJAutoProxyRegistrar,由于实现了ImportBeanDefinitionRegistrar,也就是在Spring容器启动的时候会调用registerBeanDefinitions方法;
这个是invokeBeanFactoryPostProcessors的时候执行,这个可以给Spring容器直接导入Bean的定义;然后spring在IOC的时候,就会创建对应的bean
ImportBeanDefinitionRegistrar
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
关键方法执行
#Spring-AOP之AspectJ切面理解
+ 在配置类中加入@EnableAspectJAutoProxy注解支持
(1)问题,为什么加入了@EnableAspectJAutoProxy注解后,spring-AOP就起作用了?
(1)通过使用注解后,注解内部导入了org.springframework.context.annotation.AspectJAutoProxyRegistrar类【这个类起关键作用】
+ 注解@EnableAspectJAutoProxy定义
//org.springframework.context.annotation.AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)//导入了AspectJAutoProxyRegistrar
public @interface EnableAspectJAutoProxy {}
+ AspectJAutoProxyRegistrar类干了什么事情?【@Import(AspectJAutoProxyRegistrar.class)//导入了AspectJAutoProxyRegistrar】
AspectJAutoProxyRegistrar类实现了接口 ImportBeanDefinitionRegistrar(org.springframework.context.annotation包)
+ 在spring容器初始化(refresh())的时候,会调用invokeBeanFactoryPostProcessors(beanFactory)方法
//Invoke factory processors registered as beans in the context【执行工厂后置处理器,注册一个bean在spring-上下文】
invokeBeanFactoryPostProcessors(beanFactory)
在这个方法里面就实现了对实现接口ImportBeanDefinitionRegistrar的处理【具体可以看另一篇文章针对ImportBeanDefinitionRegistrar合适处理的分析】
文章地址:https://blog.csdn.net/qqzhengwei/article/details/113102969
+ 上面执行完毕后,就会把 AspectJAutoProxyRegistrar 【完成AnnotationAwareAspectJAutoProxyCreator初始化new】
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator的registerBeanDefinitions方法
+ AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)//完成下面说的注册到spring容器中
beanName=org.springframework.aop.config.internalAutoProxyCreator 实例为 AnnotationAwareAspectJAutoProxyCreator,注册到spring-beanFactory中
+ 最终给spring容器注册了beanName=org.springframework.aop.config.internalAutoProxyCreator,实例为 AnnotationAwareAspectJAutoProxyCreator
+ 上面只是把AnnotationAwareAspectJAutoProxyCreator的beanDefinition注册到spring容器,但是这个时候bean还没有被实例化
+ AnnotationAwareAspectJAutoProxyCreator 在何时被初始化的呢?
【查看 AnnotationAwareAspectJAutoProxyCreator 类图结构】--看看他实现了什么接口,以及什么时候完成的初始化
1)、实现了 BeanFactoryAware 接口,也就是在 AnnotationAwareAspectJAutoProxyCreator spring创建这个bean的时候,会注册 beanFactory实例进来
这个时候就可以通过beanFactory放注册的bean
2)、实现了 BeanPostProcessor ,bean的后置处理器【这个都是在bean实例化的时候做的动作】
--postProcessBeforeInitialization 在bean初始化之前做的事情
--postProcessAfterInitialization 在bean实例化之后做的事情
+ org.springframework.context.support.AbstractApplicationContext的refresh()
+ registerBeanPostProcessors(beanFactory);//(注册bean的后置处理器,用来拦截bean的创建)Register bean processors that intercept bean creation.
+ PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this)
通过PostProcessorRegistrationDelegate去处理
//通过beanFactory在spring容器中把上面定义的AnnotationAwareAspectJAutoProxyCreator给找到
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//通过beanFactory-根据beanName名称(org.springframework.aop.config.internalAutoProxyCreator)去容器中获取这个bean
//getBean,去spring容器获取bean,如果spring容器找不到,就去创建;(bean的实例化过程实现)
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class)
+ getBean的执行链路
org.springframework.beans.factory.support.AbstractBeanFactory类中的方法(为beanFactory的抽象类)
1)、getBean(String name, Class<T> requiredType)
2)、doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
3)、getSingleton(String beanName, ObjectFactory<?> singletonFactory)最终还是会执行下面createBean方法
3)、sharedInstance = getSingleton(beanName, () -> {return createBean(beanName, mbd, args))};之说核心方法
4)、createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
--org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
【这里执行了BeforeInstantiation】Object bean = resolveBeforeInstantiation(beanName, mbdToUse)
//Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
5)、doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
一、循环依赖问题解决(较早暴露bean)
二、createBeanInstance 通过无参构造函数实例化bean
三、populateBean 给bean的各种属性赋值
四、initializeBean 初始化bean
1)、invokeAwareMethods 调用实现了Aware接口的方法
2)、applyBeanPostProcessorsBeforeInitialization 执行前置处理器 postProcessBeforeInitialization
3)、invokeInitMethods 调用初始化方法:例如afterPropertiesSet实现InitializingBean接口
4)、postProcessAfterInitialization 执行后置处理器 postProcessAfterInitialization
【这个后置处理器就会调用 AnnotationAwareAspectJAutoProxyCreator 的postProcessBeforeInitialization和postProcessAfterInitialization方法】
+ 以上就完成了AnnotationAwareAspectJAutoProxyCreator的创建和注册到spring容器
AnnotationAwareAspectJAutoProxyCreator实现了接口BeanPostProcessor后置处理器,也就是以后创建任何Bean的都是都会调用
----》postProcessBeforeInitialization
---》postProcessAfterInitialization
方法,这样就实现了拦截处理。
InstantiationAwareBeanPostProcessor 后置处理器作用(使用契机)
==================================【以下是在实例化之前做的事情】 doCreateBean之前做的
+ interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor
InstantiationAwareBeanPostProcessor 也是一个BeanPostProcessor,只是是BeanPostProcessor的子接口
+ AnnotationAwareAspectJAutoProxyCreator ==> InstantiationAwareBeanPostProcessor【这个叫实例化之前的后置处理器】
=========
+ org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory)
在spring容器初始化完成finishBeanFactoryInitialization
【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前都会有一个拦截的作用 因为他是一个 InstantiationAwareBeanPostProcessor 后置处理器】
【在容器AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory)执行时产生的效果】--实例化bean容器里面所有的bean
+ 遍历容器中所有的bean,依次创建getBean(beanName)对象;beanFactory的beanDefinitionNames属性
+ [+ getBean的执行链路]查看上面的getBean执行链路
+ 创建bean实例
1)、先从缓存中看看是否存在bean实例;
如果能够获取到直接从缓存中获取(单例的bean),如果不存在的话,否则创建bean;
2)、createBean创建bean
【BeanPostProcessors 是在对象创建完成,初始化前后调用】
【InstantiationAwareBeanPostProcessor 是在对象,创建之前调用】
1)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse)执行:创建bean前的,处理器
代码注释Give BeanPostProcessors a chance to return a proxy instead of the target bean instance
给BeanPostProcessors(后置处理器)一个机会,来返回一个代理对象,来替代真实的对象【代理就是在这里开始的】
+ 【这里执行了BeforeInstantiation】Object bean = resolveBeforeInstantiation(beanName, mbdToUse)
+ resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)
//执行前置
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
如果bp instanceof InstantiationAwareBeanPostProcessor 就执行后置处理器的postProcessBeforeInstantiation方法
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
执行后置--postProcessAfterInitialization
}
2)、 希望后置处理器在这里可以返回一个代理对象,如果能返回就使用代理对象bean,如果不能返回,就在创建bean;
Object beanInstance = doCreateBean(beanName, mbdToUse, args)
+ AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation方法又干了什么事情呢?
要获取代理bean这样获取
BeanFactory接口里面的常量String FACTORY_BEAN_PREFIX = "&";
BeanFactory.FACTORY_BEAN_PREFIX + beanName
1)、postProcessBeforeInstantiation
1)、判断当前bean是否已经增强
2)、在判断beanClass是否是基础类型的(Advice、Pointcut、Advisor、AopInfrastructureBean、@AspectJ)
3)、是否需要跳过shouldSkip()
1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors增强器集合】
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
2)、永远返回false
2)、创建对象 postProcessAfterInitialization
return wrapIfNecessary(bean, beanName, cacheKey); //包装如果需要的情况下
1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
2、获取到能在bean使用的增强器。
3、给增强器排序使用@Order(3)数值越小,优先级越高。越优先执行
2)、保存当前bean在advisedBeans中;
3)、如果当前bean需要增强,创建当前bean的代理对象;
1)、获取所有增强器(通知方法)
2)、保存到proxyFactory
3)、创建代理对象:Spring自动决定
JdkDynamicAopProxy(config);jdk动态代理;
ObjenesisCglibAopProxy(config);cglib的动态代理;
4)、给容器中返回当前组件使用cglib增强了的代理对象;
5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
3)、目标方法执行 ;
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
1)、CglibAopProxy.intercept();拦截目标方法的执行
2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
1)、List<Object> interceptorList保存所有拦截器
一个默认的ExposeInvocationInterceptor 和 配置的增强器;
2)、遍历所有的增强器,将其转为Interceptor;
registry.getInterceptors(advisor);
3)、将增强器转为List<MethodInterceptor>;
如果是MethodInterceptor,直接加入到集合中
如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;
3)、如果没有拦截器链,直接执行目标方法;
retVal = methodProxy.invoke(target, argsToUse)
拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
4)、如果有拦截器链,把需要执行的目标对象,目标方法,
拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
并调用 Object retVal = mi.proceed();
5)、拦截器链的触发过程;
new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()
相当于执行了父类的org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()方法
1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
拦截器链的机制,保证通知方法与目标方法的执行顺序;
public Object proceed() throws Throwable {
//currentInterceptorIndex初始化是-1,interceptorsAndDynamicMethodMatchers拦截器链集合
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//一个一个拦截器链的取
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
# 总结
1)、 @EnableAspectJAutoProxy 开启AOP功能
2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器的创建流程:
1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
1)、创建业务逻辑组件和切面组件
2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
3)、组件创建完之后,判断组件是否需要增强
是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
5)、执行目标方法:
1)、代理对象执行目标方法
2)、CglibAopProxy.intercept();
1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
3)、效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知
- 拦截器链执行过程
拦截器返回通过
- 拦截器链
- 增强器 InstantiationModelAwarePointcutAdvisor接口的的实例InstantiationModelAwarePointcutAdvisorImpl
动态代理创建
org.springframework.aop.framework.DefaultAopProxyFactory创建代理
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);//JDK动态代理
}
return new ObjenesisCglibAopProxy(config);//Cglib动态代理
}
else {
return new JdkDynamicAopProxy(config);
}
}
AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
⬇️
//实例化剩下的不是懒加载的 单实例Bean
finishBeanFactoryInitialization(beanFactory);
⬇️
beanFactory.preInstantiateSingletons();
⬇️
// ? 构造器执行,创建一个Bean
getBean(beanName);
⬇️
doGetBean
⬇️
getSingleton
⬇️
doCreateBean{
//将需要Autowired 的属性方法执行一遍
populateBean(beanName, mbd, instanceWrapper);
initializeBean(beanName, exposedObject, mbd){
// aware 方法执行,给实现了xxAware的方法设置值
invokeAwareMethods(beanName, bean);
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName){
beanProcessor.postProcessBeforeInitialization(result, beanName){
invokeAwareInterfaces(bean){
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
}
}
// 初始化方法,执行init
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
}
posted on 2021-01-27 09:21 1763392456 阅读(138) 评论(0) 编辑 收藏 举报