Spring的AOP流程

xiaoxiao2021-02-28  101

目录

1、AOP基本概念

2、AOP应用场景

3、AOP的实践

4、AOP 切面执行顺序分析

5、AOP使用注意事项

6、AOP的设计思想

7、源码解析

7.1、后置处理器AnnotationAwareAspectJAutoProxyCreator的创建

7.2、增强业务Bean的创建

7.3、调用执行阶段

8、小结


前言         一种技术的诞生,主要是思维模式的改变,有C的 面向过程,到C++/java的面向对象,到面向类,面向方法编程的AOP,最后到面向服务编程的微服务。         Spring的优秀设计之一就是AOP,通过一个注解就可以实现对某个方法的执行前后的功能增强。面向切面编程,提供另外一个角度来思考程序的结构,是一种编程思想,程序模块化思维,找出多个模块或者方法之间有一定规律的代码,开发时将其拆开,运行时将其再合并,解决了面向对象编程的不足。  

1、AOP基本概念

(1). A spect 【切面】:通常是一个类,里面可以定义切入点和通知; (2). JointPoint 【连接点】:程序执行过程中明确的点,一般是方法的调用; (3). Advice 【通知】:AOP在特定的切入点上执行的增强的处理,有before/after/around/afterRetuing/afterThrowing; (4). PointCut (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式。 (5). Excution 表达式:定义切入点规则,多个方法形成一个切面;   AOP之Execution表达式解释 例:execution(* *.*(..)) 第一个*:代表的是方法返回的类型 第二个*: 代表扫描的包路径; 第三个*:包路径下的方法名,(..)代表方法的参数; 例如: @Around("@annotation(com.king..LogAspect)")                                 //容器中加了LogAspect注解的类才拦截; @Before("execution(public int com.king.aop.Calc.div(int,int))")             //拦截div(intent)方法,返回参数是int; @Before("execution(public int com.king.aop.Calc.*(..))")                    //拦截包下的所有的方法; @Around("execution(public int com.king.aop.Calc.*(..)) && @annotation(log)")  //将注解 DoSomething作为一个参数传递进来

2、AOP应用场景

Spring中各种注解功能的实现,例如事务@Transactional/@Async/@Aspect等等太多,使业务和功能代码解耦,进行无侵入性的代码增强; 统一请求、参数校验,日志和异常处理; 权限验证,数据源的切换等等;     主要作用:将业务和非业务功能代码分离,提高代码的复用性,使代码逻辑简单可读,让开发人员能更好的专注于业务开发而不是非业务技术代码;

3、AOP的实践

实例演示:切面类 @Component @Aspect public class LogAspect {     //抽取公共切入点表达式     //1 如果是该应用内,只需要@Before("pointCut()")     //2 如果是其他切面类需要引用,需要写上切面类的路径和方法     @Pointcut("execution(public int com.king.aop.Calc.*(..))")     public void pointCut() {     }     @Before("execution(public int com.king.aop.Calc.div(int,int))")     public void logStart(JoinPoint joinPoint) {         System.out.println("Before 除法运行开始,方法名:" + joinPoint.getSignature().getName() + "  参数列表: {" +                 Arrays.asList(joinPoint.getArgs()) + "}");     }     @After("pointCut()")     public void logEnd() {         System.out.println("After 除法运行结束。。。。");     }     @AfterReturning(value = "com.king.aop.LogAspect.pointCut()", returning = "result")     public void logReturn(Object result) {         System.out.println("AfterReturning  除法正常返回,结果为:" + result);     }         //测试分母为0的异常情况     @AfterThrowing(value = "pointCut()", throwing = "exception")     public void logAfterThrowing(Exception exception) {         System.out.println("AfterThrowing 除法运算异常 " + exception);     }     @Around(value = "pointCut() && @annotation(logAnnotation)  ")     public Object logAround(ProceedingJoinPoint proceedingJoinPoint,BaseLog logAnnotation) {         System.out.println("logAround 执行目标方法之前: ");         try {//这里必须手动调用             Object obj = proceedingJoinPoint.proceed();             System.out.println("logAround 目标方法执行之后: ");             return obj;         } catch (Throwable throwable) {             throwable.printStackTrace();         }         return -1;     } }

切面注解

解析注解的类信息: 注解分为 3 类: @Target({ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface BaseLog { } 一类是 java 自带的标准注解:包括常用的@Controller @Service @Repository 二类是元注解,元注解是用于定义注解的注解,包括 @Retention(表明注解被保留的阶段) 源代码-编译器 - 运行期 什么作用范围,生命周期? @targe(标明注解使用的范围) 什么范围使用? @Inherited(标明注解可继承) 能否被继承? @Documented(标明是否生成javadoc文档) 是否包含在javadoc中?  三类是自定义注解,根据自己的定义需求注解 注解的作用域: source:存在java代码级别,编译为class就无效了;  @Override,格式检查,是否覆盖实现了接口的方法 class:编译期级别,帮我们生成get和set方法; lambook @Data Runtime类型:运行期间产生作用 @Service,很常见

拦截方法

public class Calc {     //业务逻辑     @BaseLog     public int div(int i, int j) {                  return i / j;     } }

配置类

@Configuration @EnableAspectJAutoProxy public class ConfigAop {     @Bean     public Calc getCalc(){         return new Calc();     }     @Bean     public LogAspect getAspect(){         return new LogAspect();     } }

测试类:

@Test public void aopTest() {     AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(com.aop.ConfigAop.class);     Calc calc = app.getBean(Calc.class);     System.out.println("result: "+ calc.div(8, 2)); }

正常运行结果8/2:

logAround 执行目标方法之前: Before 除法运行开始,方法名:div  参数列表: {[8, 2]} div running logAround 目标方法执行之后: After 除法运行结束。。。。 AfterReturning  除法正常返回,结果为:4 result: 4

异常运行:输入2/0的结果:

logAround 执行目标方法之前: Before 除法运行开始,方法名:div  参数列表: {[2, 0]} div running java.lang.ArithmeticException: / by zero     at com.enjoy.aop.aop.Calc.div(Calc.java:15) After 除法运行结束。。。。 AfterReturning  除法正常返回,结果为:-1 reslut: -1

通过调试,你会发现Calc是经过增强的Bean,它其实变成了一个实现了Advised接口的代理类,并不是原生的Calc类,所以才会运行自己编写的切面类。

4、AOP 切面执行顺序分析

从上面的例子可以看出,AOP执行顺序: try {      1、 环绕前置通知;@Around       2、 前置通知;   @Before            3、 执行目标方法; method.invoke()      4、 环绕后置通知;@Around      5、 执行返回通知;@After }catche(Exception e){      5.1、执行异常通知;@AfterThrowing  没有异常不打印,有异常替换@After }finally{      6、执行后置通知;@AfterReturning }

AOP的执行流程图如下:

思考:如果同一个方法被两个Aspect所拦截,那么它们的先后顺序怎么确定呢,关系会根据调用顺序嵌套执行? [Aspect-1] logAround 执行目标方法之前: [Aspect-1] Before 除法运行开始:div  参数列表: {[8, 2]} [Aspect-2] logAround 执行目标方法之前: [Aspect-2] Before 除法运行开始:div  参数列表: {[8, 2]} Ok [Aspect-2] logAround 目标方法执行之后: [Aspect-2] After 除法运行结束。。。。 [Aspect-2] AfterReturning  除法正常返回,结果为:4 [Aspect-1] logAround 目标方法执行之后: [Aspect-1] After 除法运行结束。。。。 [Aspect-1] AfterReturning  除法正常返回,结果为:4

如果要确定两个切面的执行顺序,可以给aspect添加@Order注解,值越小优先级越高。

@Order(1) @Component @Aspect public class ParamCheckAspect1 {     // ... } @Order(2) @Component @Aspect public class LogAspect2 {     // ... }

这样就先执行参数校验的切面ParamCheckAspect1,然后执行日志打印的切面拦截LogAspect2,控制了其执行顺序。

5、AOP使用注意事项

1、要使用 spring的AOP功能一定要对代理的对象进行增强,否则注解就会失效,例如事务的本地的this调用,没有增强就会失效;例如执行如下: @Test public void aopTest() {     AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(com.aop.ConfigAop.class);     Calc calc = new Calc();     System.out.println("result: "+ calc.div(8, 2)); //这时候日志的切面是不生效的,没有被spring代理,没有增强; }

2、Final方法不能被通知,因为它final不能被重写,动态代理的CGlib不能重写final方法;

3、对于@Around这个注解,不管它有没有返回值,内部都必须要调用一下pjp.proceed(),否则目标方法将不会执行,也就是@Before无法执行;如果我们去掉这个执行方法,运行结果如下:

注释掉://Object obj = proceedingJoinPoint.proceed(); @Before和目标方法不会执行,运行结果: logAround 执行目标方法之前: logAround 目标方法执行之后: After 除法运行结束。。。。 AfterReturning  除法正常返回,结果为:-1 reslut: -1

可以看到,结果打印没有方法的执行。

 

6、AOP的设计思想

核心思路就是: @EnableAspectJAutoProxy开启aop功能; 第一步:首先创建AOP后置处理器- AnnotationAwareAspectJAutoProxyCreator,加工增强我们的bean;因为它要对业务bean的创建进行拦截,必须先创建; 第二步:然后再创建剩余的单实例bean,业务bean; 第三步:接着在创建单实例业务bean进行初始化的时候,通过后置处理器postProcessor就会对其做增强; 第四步:通过动态代理的到一个增强的代理对象; 第五步:通过代理对象来执行目标方法 , CglibAopProxy. intercept() + proceed(); (1) 得到目标方法的拦截器链(增强器包装成拦截器 MethodInterceptor ); (2) 利用拦截器链式机制,一次进入每一个拦截器进行执行; (3) 执行结果顺序: 正常执行:环绕前置通知AroundBefore -> 前置通知Before-> 环绕后置通知AroundAfter  -> 目标方法invoke()  -> 后置通知After  -> 返回通知 AfterReturning 异常执行:环绕前置通知 AroundBefore -> 前置通知 Before -> 环绕后置通知 AroundAfter  -> 目标方法 invoke() -> 异常通知 AfterThrowing

7、源码解析

一切从入口开启AOP的注解开始: @Configuration @EnableAspectJAutoProxy public class ConfigAop {     @Bean     public Calc getCalc(){         return new Calc();     }     @Bean     public LogAspect getAspect(){         return new LogAspect();     } }

7.1、后置处理器AnnotationAwareAspectJAutoProxyCreator的创建

查看EnableAspectJAutoProxy源码实现: @Target(ElementType.TYPE)           //在什么地方使用?方法/类/字段 @Retention(RetentionPolicy.RUNTIME) //什么时间生效?class文件 @override- - 编译期间 lambook- 运行期间 @Documented                         //是否加入到javaDoc中 @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy {        //判断是用jdk还是CGLib动态代理    boolean proxyTargetClass() default false;        //是否暴露aop动态代理,在同类中动态代理的方法调用的时候就需要用到它;    boolean exposeProxy() default false; }

继续查看AspectAutoProxyRegistrar源码,发现其通过ImportBeanDefinitionRegistrar向容器中注入了一个十分重要的组件:AnnotationAwareAspectJAutoProxyCreator.class,它贯穿了整个aop的全过程;

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {    /**     * Register, escalate, and configure the AspectJ auto proxy creator based on the value     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing     * {@code @Configuration} class.     */    @Override    public void registerBeanDefinitions(          AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {       AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);       AnnotationAttributes enableAspectJAutoProxy =             AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);       if (enableAspectJAutoProxy != null) {          if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {             AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);          }          if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {             AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);          }       }    } }@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(       BeanDefinitionRegistry registry, @Nullable Object source) {         //开始向容器中注入组件:AnnotationAwareAspectJAutoProxyCreator    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } 看一下AnnotationAwareAspectJAutoProxyCreator的作用? 这里先看一下它的继承关系: public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {     public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {         public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {             public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport                       implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

从这里可以看出,它是一个后置处理器;主要关注我们的bean初始化的前后需要做的事情,自动装配BeanFactory

BeanFactory : Spring容器的顶层接口,实现Bean的创建,获取,生命周期的管理等等; SmartInstantiationAwareBeanPostProcessor :Bean的后置处理器,也是一个很重要的组件,主要用来对业务方法进行Bean的代理增强;  

7.2、增强业务Bean的创建

思考:如何用后置处理器和动态代理来生成我们增强的bean实例呢? 重点分析div()方法是如何跟AnnotationAwareAspectJAutoProxyCreator相结合的。 public class Calc {     //业务逻辑     @BaseLog     public int div(int i, int j) {         return i / j;     } }

一切从容器的启动refresh开始:

@Override public void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {       // Prepare the bean factory for use in this context.       prepareBeanFactory(beanFactory);       try {          // Allows post-processing of the bean factory in context subclasses.          postProcessBeanFactory(beanFactory);          // Invoke factory processors registered as beans in the context.          //调用所有注册的BeanFactoryPostProcessor的Bean定义信息,但是未创建未初始化;          invokeBeanFactoryPostProcessors(beanFactory);          // Register bean processors that intercept bean creation.          //BeanPostProcessor是Bean后置处理器的创建,用于监听容器触发的事件aop相关bean的创建,aop相关的bean就是在这里注册创建实例化;          //AnnotationAwareAspectJAutoProxyCreator.class就是在这里创建实例化;          registerBeanPostProcessors(beanFactory);          // Check for listener beans and register them.          registerListeners();          // Instantiate all remaining (non-lazy-init) singletons.          //相关业务bean的创建,也就是计算类calc类的创建          finishBeanFactoryInitialization(beanFactory);          // Last step: publish corresponding event.          finishRefresh();       } 创建剩余的保留的单实例bean: protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {    // Initialize conversion service for this context.    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&          beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {       beanFactory.setConversionService(             beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));    }    // Instantiate all remaining (non-lazy-init) singletons.    beanFactory.preInstantiateSingletons(); }

继续初始化bean:

@Override public void preInstantiateSingletons() throws BeansException {     String FACTORY_BEAN_PREFIX = "&";    //得到所有的bean的名字    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);    // Trigger initialization of all non-lazy singleton beans...    for (String beanName : beanNames) {       RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);       if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {          if (isFactoryBean(beanName)) {             Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);             if (bean instanceof FactoryBean) {                final FactoryBean<?> factory = (FactoryBean<?>) bean;                boolean isEagerInit;                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {                   isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)                               ((SmartFactoryBean<?>) factory)::isEagerInit,                         getAccessControlContext());                }                else {                   isEagerInit = (factory instanceof SmartFactoryBean &&                         ((SmartFactoryBean<?>) factory).isEagerInit());                }                if (isEagerInit) {                   getBean(beanName);                }             }          }          else {//循环获取这个bean             getBean(beanName);          }       }    } 继续getBean(): @Override public Object getBean(String name) throws BeansException {    return doGetBean(name, null, null, false); }

这里主要关注 Calculator的创建,是如何增强的?

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,       @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {    final String beanName = transformedBeanName(name);    Object bean;    // Eagerly check singleton cache for manually registered singletons.    Object sharedInstance = getSingleton(beanName);    if (sharedInstance != null && args == null) {         // Create bean instance. //创建bean实例         if (mbd.isSingleton()) {             //第一次根据bean name去拿单实例bean,肯定没有            sharedInstance = getSingleton(beanName, () -> {               try {//创建bean实例                      return createBean(beanName, mbd, args);                   }            }

获取calculator的bean,并判断有无增强处理:

@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)       throws BeanCreationException {    try {       // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.      //给个机会返回代理类对象;      //对bean的前置处理器,遍历出所有的postProcessBean;       Object bean = resolveBeforeInstantiation(beanName, mbdToUse);         //第一步:创建一个单实例bean;普通的实例bean       if (bean != null) {          return bean;       }    }         try { //第二步:后置处理器返回一个动态代理        Object beanInstance = doCreateBean(beanName, mbdToUse, args);        if (logger.isTraceEnabled()) {           logger.trace("Finished creating instance of bean '" + beanName + "'");        }        return beanInstance; } @Nullable  //初始化之前判断是否有后置处理器的增强; protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {    Object bean = null;    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {       // Make sure bean class is actually resolved at this point.         //判断该bean Calcutor是否是实现了BeanPostProcessor,显然满足条件是一个后置处理,加了aop的功能       if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {          Class<?> targetType = determineTargetType(beanName, mbd);          if (targetType != null) {             //前置处理器             bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);             if (bean != null) {              //后置处理器                bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);             }          }       }       mbd.beforeInstantiationResolved = (bean != null);    }    return bean; } // 找到Calcutor的后置处理器 AnnotationAwareAspectJAutoProxyCreator 进行增强; //前置处理器主要是 拿到@Aspect中的所有切面方法 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {     //拿到bean的名字,cachekey ==Calcutor     Object cacheKey = getCacheKey(beanClass, beanName);    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);    if (targetSource != null) {       if (StringUtils.hasLength(beanName)) {          this.targetSourcedBeans.add(beanName);       }        //找到 Calcutor 的增强器,主要是拦截的4个切面类       Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);       Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);       this.proxyTypes.put(cacheKey, proxy.getClass());       return proxy; //至此-返回一个代理对象,但是before不会产生任何代理    } } //找 Calcutor的增强器 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {    List<Advisor> candidateAdvisors = findCandidateAdvisors();         //获取合适的增强器,就是我们编写的before - after - around的切面类    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);    extendAdvisors(eligibleAdvisors);    if (!eligibleAdvisors.isEmpty()) {         //对增强器进行排序,因为方法调用是有时机顺序的,前面也提到验证过,before-after-return       eligibleAdvisors = sortAdvisors(eligibleAdvisors);    }    return eligibleAdvisors; }

通过反射创建一个增强的代理bean,最后生成的这个Bean就是加入切面类增强的Bean。

*/ protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)       throws BeanCreationException {    // Instantiate the bean.    BeanWrapper instanceWrapper = null;    if (mbd.isSingleton()) {       instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);    }    // 第一步:通过反射创建bean    if (instanceWrapper == null) {       instanceWrapper = createBeanInstance(beanName, mbd, args);    }     Object exposedObject = bean;     try {        //第二步:给实例bean赋值        populateBean(beanName, mbd, instanceWrapper);        //第三步:给bean初始化        exposedObject = initializeBean(beanName, exposedObject, mbd);     }

进入到后置处理器:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {    Object wrappedBean = bean;    if (mbd == null || !mbd.isSynthetic()) {//初始化前置处理器       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);    }    try { //调用方法       invokeInitMethods(beanName, wrappedBean, mbd);    }    catch (Throwable ex) {       throw new BeanCreationException(             (mbd != null ? mbd.getResourceDescription() : null),             beanName, "Invocation of init method failed", ex);    }    if (mbd == null || !mbd.isSynthetic()) {//初始化后置处理器       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);    }    return wrappedBean; }

进入后置处理器,后置处理器的作用:

拿到所有的通知方法; 创建增强的动态代理对象;Calcutor对象; @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {    if (bean != null) {       //从缓存中拿到bean的名字       Object cacheKey = getCacheKey(bean.getClass(), beanName);       if (!this.earlyProxyReferences.contains(cacheKey)) {          return wrapIfNecessary(bean, beanName, cacheKey);       }    }    return bean; }

如果对象有增强,找到增强器,因为切面类不是实现的接口,所以开始通过Cglib创建代理对象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {    // Create proxy if we have advice. //先获取排好序的通知类bean,创建增强代理对象    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; } //创建动态代理类,创建aop增强bean的创建 public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {    @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)) {             //方式一:如果有接口,就使用 jdk动态代理;             return new JdkDynamicAopProxy(config);          }             //方式二:如果没有接口,就使用CGLib动态代理          return new ObjenesisCglibAopProxy(config);       }       else {          return new JdkDynamicAopProxy(config);       }    } }

至此,我们的增强bean Calc就创建完成了。

7.3、调用执行阶段

此时调用会调用动态代理增强的实例bean,所以进入拦截方法,注意如果不是从容器获取的增强的bean是aop是无效的。 进入拦截类方法: CglibAopProxy.interceptor(); 、 //通过cglib创建动态代理类,获取相关的切面拦截方法 class CglibAopProxy implements AopProxy, Serializable {    // Constants for CGLIB callback array indices    private static final int AOP_PROXY = 0; @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {    Object oldProxy = null;    boolean setProxyContext = false;    Object target = null;     //第一步:拿到我们的目标类:calculator类;    TargetSource targetSource = this.advised.getTargetSource();    try {//暴露动态代理,同类里调用事务注解失效就是在这里设置解决的;       if (this.advised.exposeProxy) {          // Make invocation available if necessary.          oldProxy = AopContext.setCurrentProxy(proxy);          setProxyContext = true;       }       // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...       target = targetSource.getTarget();       Class<?> targetClass = (target != null ? target.getClass() : null);         //第二步:拿到拦截链       List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);       Object retVal;       // Check whether we only have one InvokerInterceptor: that is,       // no real advice, but just reflective invocation of the target.       if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {          Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);          retVal = methodProxy.invoke(target, argsToUse);       }       else {          // We need to create a method invocation…           //第三步:调用具体的方法,around的时候需要手动的调用我们的方法,proceed()就是调用方法本身;          retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();       }       retVal = processReturnType(proxy, target, method, retVal);       return retVal;    }    finally {       if (target != null && !targetSource.isStatic()) {          targetSource.releaseTarget(target);       }       if (setProxyContext) {          // Restore old proxy.          AopContext.setCurrentProxy(oldProxy);       }    } }

获取拦截链的拦截通知方法,也就是Aspect中写的拦截方法,这里获取到:

@Override//拿到所有的通知方法 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(       Advised config, Method method, @Nullable Class<?> targetClass) {    // This is somewhat tricky... We have to process introductions first,    // but we need to preserve order in the ultimate list.    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();    Advisor[] advisors = config.getAdvisors();     //第一步:拿到通知方法的长度    List<Object> interceptorList = new ArrayList<>(advisors.length);    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());    Boolean hasIntroductions = null;    for (Advisor advisor : advisors) {       if (advisor instanceof PointcutAdvisor) {          // Add it conditionally.             if (mm instanceof IntroductionAwareMethodMatcher) {                if (hasIntroductions == null) {                   hasIntroductions = hasMatchingIntroductions(advisors, actualClass);                }             if (match) {                 //第二步:将Inteceptor转换为MethodInterceptor                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                if (mm.isRuntime()) {                   // Creating a new object instance in the getInterceptors() method                   // isn't a problem as we normally cache created chains.                   for (MethodInterceptor interceptor : interceptors) {                      interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));                   }                }    return interceptorList;  }   栈式调用我们具体通知方法: @Override @Nullable public Object proceed() throws Throwable {    // We start with an index of -1 and increment early.     //第一步:通过i++来取我们的通知拦截方法    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);    } }

     到此,我们创建和执行阶段就完全解析完了。虽然搞了好久,不过好似打通了任督二脉,舒坦。

8、小结

        其实Spring中放眼望去,大部分都是基于注解实现的功能,例如@Transactional/@Async/@Controller/@Component/@Service@/Respositoy等等,其设计思路和aop的实现的思路大致一样,都是遵循同样的套路。 AOP注解切面编程的实现套路: 第一步:通过@Enablexxxx来为容器中先注册一个有关功能的代理创建器@xxxAutoProxyCreator,一般这个处理器会实现我们的后置处理器接口postProcessor; 第二步:实例化我们的业务bean,通过后置处理器postProcessor在bean初始化后的afterInitialized对bean进行增强;通过动态代理创建增强bean注入到容器; 第三步:通过动态代理调用我们的增强的bean代理对像,实现增强的业务功能;     水滴石穿,积少成多。学习笔记,内容简单,用于复习,梳理巩固。    
转载请注明原文地址: https://www.6miu.com/read-82853.html

最新回复(0)