SpringAOP原理分析

Spring AOP切面原理

核心注解@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

核心导入了AspectJAutoProxyRegistrar组件,进一步分析AspectJAutoProxyRegistrar组件

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@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);
			}
		}
	}

}

发现AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口

ImportBeanDefinitionRegistrar是Spring提供来用于自动装配的接口 核心方法有2个主要是传入扫描类的注解信息,Spring的BeanDefinitionRegistry 通过这个registry可以注册组件

public interface ImportBeanDefinitionRegistrar {
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}
    
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}
}

明白了 BeanDefinitionRegistry 的作用进一步研究这个方法是AOP实现的核心AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

又调用了AOPConfigUtils的内部方法最终追踪到

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
// 注册AnnotationAwareAspectJAutoProxyCreator bean定义信息
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 首先判断一下bean工厂里面有没有 AUTO_PROXY_CREATOR_BEAN_NAME这个bean 真实名称叫org.springframework.aop.config.internalAutoProxyCreator 第一次进来肯定没有
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
// 开始创建bean
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
  • 判断工厂中是否已经存在org.springframework.aop.config.internalAutoProxyCreator这个bean定义信息
  • 没有开始创建并注册调用 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  • beanDefinition 需要注册一个AnnotationAwareAspectJAutoProxyCreator的组件
  • 进入DefaultListableBeanFactory#registerBeanDefinition方法 此处执行完毕之后bean工厂中已经加入了名称为org.springframework.aop.config.internalAutoProxyCreator且类型为AnnotationAwareAspectJAutoProxyCreator的BeanDefinition信息,用于等下Spring启动之后创建这个bean

现在需要重点研究AnnotationAwareAspectJAutoProxyCreator 这个类干了什么

查看AnnotationAwareAspectJAutoProxyCreator 的继承树image-20210311102722975

  • AnnotationAwareAspectJAutoProxyCreator 核心需要注册的类也是整个AOP原理的入口

  • BeanFactoryAware 接口是spring aware接口体系中的一个,实现了该接口的类Spring会把BeanFactory传递给该组件,拿到BeanFactory就可以使用BeanFactory进行组件的注册

  • SmartInstantiationAwareBeanPostProcessor 核心继承类,他又继承了InstantiationAwareBeanPostProcessor 该类中有2个核心方法

    • postProcessBeforeInstantiation 在Spring创建bean之前能够通过这个方法返回一个代理对象来替代需要创建的bean,这次是Spring AOP代理对象的核心,如果此方法返回了对象,Spring会直接拿加强过的bean作为组件注册,不会再注册我们自己写的bean信息
    public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    
    	@Nullable
    	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    		return null;
    	}
    
    	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    		return true;
    	}
    
    }
    
  • BeanPostProcessor bean的后置处理器 spring功能扩展的核心,在bean初始化前后可以对bean做一些增强 如@Autowire注解就有对应了AutowiredAnnotationBeanPostProcessor来进行对bean的属性赋值的增加

以上分析AnnotationAwareAspectJAutoProxyCreator 的主要功能,下面进入Spring自动注册流程的分析


查看主类的run方法

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

  • 获取SpringApplicationRunListener 并在合适的地方触发这些listener
  • 在准备创建IOC环境之前 listener start方法
  • 在准备ConfigurableEnviroment 之前调用listeners.environmentPrepared
  • 准备环境
  • 根据项目类型创建不同的上下文 如MVC上下文还是WEB-FLUX上下文
  • 准备上下文之前 listeners.contextPrepared(context)
  • 准备上下文
  • 准备上下文之后 listeners.contextLoaded(context)
  • 刷新上下文 refreshContext
  • afterRefresh 方法
  • listener.started
  • 执行ApplicationRunner和 CommandRunner

核心refresh方法

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 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.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
  • 刷新准备

  • 获取beanFactory

  • 准备beanFactory

  • 执行beanFactory的postProcessor

  • 注册BeanPostProcessor AOP org.springframework.aop.config.internalAutoProxyCreator核心逻辑在此处体现 包括了动态道理底层

    • 先注册带优先级和排序priorityOrderedPostProcessors
    • 在注册带排序的orderedPostProcessors
    • 最后注册普通的PostProccessorts
  • 其中跟AOP相关的核心BeanPostProcessor的创建就在这里

    image-20210312102439534

    • 调用底层beanfactory的getBean 方法 底层有调用了doGetBean -> getSingleton获取单实例的bean

      	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      		// Quick check for existing instance without full singleton lock
      		Object singletonObject = this.singletonObjects.get(beanName);
      		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      			singletonObject = this.earlySingletonObjects.get(beanName);
      			if (singletonObject == null && allowEarlyReference) {
      				synchronized (this.singletonObjects) {
      					// Consistent creation of early reference within full singleton lock
      					singletonObject = this.singletonObjects.get(beanName);
      					if (singletonObject == null) {
      						singletonObject = this.earlySingletonObjects.get(beanName);
      						if (singletonObject == null) {
      							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      							if (singletonFactory != null) {
      								singletonObject = singletonFactory.getObject();
      								this.earlySingletonObjects.put(beanName, singletonObject);
      								this.singletonFactories.remove(beanName);
      							}
      						}
      					}
      				}
      			}
      		}
      		return singletonObject;
      	}
      
    • 底层先从Spring的一级缓存 singletonObjects 中找有没有这个bean,第一次获取肯定没有

    • 然后判断从一级缓存拿到的bean是不是为空 并且正在创建 如果正在创建尝试从二级缓存中拿 (此处逻辑是Spring 处理循环依赖的核心)

      • 如果二级缓存 singletonObjects 也没有,再判断是否是需要早起暴露的bean
      • 如果是加锁从三级缓存singletonFactories 拿到objectFactory然后调用objectFactory的getObject 方法生成一个bean
      • 然后 移动到二级缓存earlySingletonObjects 并将三级缓存singletonFactories 从删除这个引用
    • 第一次创建AOP的beanPostProcessor其实没有走上面逻辑,getSingleton直接返回null

    image-20210312103353622

  • 下面开始创建bean,创建之前先标记当前bean被创建了

    if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
    }
    
  • 然后获取bean的定义信息

    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);
    
  • 然后获取是否存在依赖其他bean 如果有遍历获取

    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        for (String dep : dependsOn) {
            if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            registerDependentBean(dep, beanName);
            try {
                getBean(dep);
            }
            catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
        }
    }
    
  • 判断是否是需要创建单例的bean如果是调用createBean创建

    	@Override
    	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		if (logger.isTraceEnabled()) {
    			logger.trace("Creating instance of bean '" + beanName + "'");
    		}
    		RootBeanDefinition mbdToUse = mbd;
    
    // 省略
    
    		try {
    			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. AOP的核心在于这里 Spring在bean创建之前调用BeanPostProcessor的postBeforeInstantiation方法让BeanPostProcessor尝试自己返回一个代理对象的bean 还不是自己去创建
    			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    			if (bean != null) {
                    // 如果代理对象返回了bean 直接返回 没有就继续调用doCreateBean方法进行创建
    				return bean;
    			}
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
    					"BeanPostProcessor before instantiation of bean failed", ex);
    		}
    
    		try {
    			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    			if (logger.isTraceEnabled()) {
    				logger.trace("Finished creating instance of bean '" + beanName + "'");
    			}
    			return beanInstance;
    		}
    		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    			// A previously detected exception with proper bean creation context already,
    			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
    			throw ex;
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(
    					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    		}
    	}
    
  • 其实在我们创建AOP的BeanPostProcessor中还没有任何BeanPostProcessor可以拦截我们创建代理对象.但是这里的逻辑是我们自定义切面的核心 我们自己的bean会在创建以前被AOP的beanPostProcessor通过pointCut逻辑进行拦截,进行对我们的bean进行加强,稍后详细分析

  • 因为没有任何BeanPostProcessor 返回了代理对象的bean,继续进入doCreateBean

    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
  • createBeanInstance创建bean实例

    • 进去判断是否需要自动注入到参的构造器
    • 如果没有特殊处理走无参构造器
    • return instantiateBean(beanName, mbd);
  • instantiateBean底层就调用了Spring的BeanUtils工具类调用反射创建无参构造器

  • 执行applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

  • 属性赋值populateBean(beanName, mbd, instanceWrapper); 如果内部需要注入bean再调用getSingleton去创建如果没有创建

  • 执行初始化方法 invokeInitMethods

  • 执行BeanPostProcessor的后置处理器 postProcessAfterInitialization方法

  • 将beanPostProccessor加入到beanfactory

  • 此时org.springframework.aop.config.internalAutoProxyCreator已经注册到了容器中


@Aspect
@Component
public class AopPointCut {
    @Pointcut("execution(public * com.corn.turorial.spring.aop.AopTestService.*(..))")
    private void pointCut() {
    }

    @Before(value = "pointCut()")
    public void before() {
        System.out.println("前置通知...");
    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前通知..");
        Object returnData = null;
//        returnData = point.proceed();

        try {
            returnData = point.proceed();
        } catch (Throwable throwable) {
            System.out.println("方法出现了异常!");
        }
        System.out.println("环绕后通知..");
        return returnData;
    }

    @After(value = "pointCut()")
    public void after() {
        System.out.println("后置通知...");
    }

    @AfterReturning(value = "pointCut()")
    public void afterReturning() {
        System.out.println("返回通知...");
    }

    @AfterThrowing(value = "pointCut()")
    public void afterThrowing() {
        System.out.println("异常通知...");
    }
}
@Component
public class AopTestService {
    public void testAop() {
//        int a = 1/0;
        System.out.println(" invoke com.corn.turorial.spring.aop.AopTestService.testAop !");
    }
}
  • 然后我们在研究这个beanPostProcessor是如何增加我们的类

  • 直接定位到refresh方法的finishBeanFactoryInitialization(beanFactory); 初始化剩下的bean

    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
        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) {
                        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 {
                    getBean(beanName);
                }
            }
        }
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }
    
  • 此时我们关心我们自己的bean 判断是不是抽象的 是不是单例 是不是懒加载 然后判断是不是一个以&开头的工厂bean我们不是走getBean逻辑

    image-20210312143927559

  • 本质上跟我们直接创建beanPostProcessor类似

    • 尝试从一级缓存singletonObjects中拿

    • 没有判断是否是单例的 是的话调用getSingleton的重载方法 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)

      image-20210312150043973

    • 进入查看createBean 类似一样的步骤 最核心跟普通bean不一样是resolveBeforeInstantiation方法 此时会进入AOP的 beanPostProcessor返回一个加强的bean

      image-20210312150408282

    • 判断是不是InstantiationAwareBeanPostProcessor

      protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
               if (result != null) {
                  return result;
               }
            }
         }
         return null;
      }
      
    • 找到AOP增加的beanPostProcessor

      image-20210312150754963

    • 进入postProcessBeforeInstantiation方法

      • 判断当前bean是否在advisedBean中是否需要增强
      • 判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean或者是否是切面
      • 是否需要跳过
        • 获取候选增强器 切面的增强通知方法 【List candidateAdvisors】
        • 每个封装的通知方法增强器是 InstantiationModelAwarePointcutAdvisor
        • 判断每个增强器是否是 AspectJPointcutAdvisor
    • 进入postProcessAfterInitialization方法

      • wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下
      • 获取当前bean的所有增强器 specificInterceptors
        • 获取候选的所有增强器 (根据切入点获取需要切入方法)
        • 获取bean能使用的增强器
        • 增强器排序
      • 保存当前bean的adviseBeans
      • 如果当前bean需要增强,创建当前bean的代理对象
        • 获取所有增强器
        • 保存到proxyFactory中
        • 创建代理对象 Spring 底层有两种代理模式JDK JdkDynamicAopProxy 和 CGLIB ObjenesisCglibAopProxy
        • 给容器中返回当前组件使用cglib增强代理对象
        • 以后容器中获取的就是这个组件的代理对象,执行目标方法,代理对象就会执行通知方法

    目标方法执行

    • 容器中保存了组件的代理对象,对象保存了详细信息(增强器,目标对象等)
    • CglibAopProxy.intercept();拦截方法执行
    • 根据ProxyFactory对象获取将要执行的目标方法拦截器
    • List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    • 遍历所有增强器转换为Interceptor registry.getInterceptors(advisor);
    • 将增强器转为List
    • 如果没有拦截器直接执行目标方法
    • 如果有拦截器 将目标对象和目标方法传入 CglibMethodInvocation对象 调用 并调用 Object retVal = mi.proceed();
    • 拦截器链的触发过程
      • 如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组大小-1相等(说明已经执行到了最后一个拦截器) 执行目标方法
      • 链式获取每一个拦截器,执行拦截器的invoke方法,每个拦截器等待下一个拦截器执行完毕返回 递归调用,保证通知方法与目标方法的调用顺序

    总结

    • @EnableAspectJAutoProxy 开启AOP
    • @EnableAspectJAutoProxy 向容器中注册一个组AnnotationAwareAspectJAutoProxyCreator
    • AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
    • 容器创建过程
      • registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
      • finishBeanFactoryInitialization 初始化剩下的单实例bean
        • 创建业务逻辑和切面组件
        • AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
        • 组件创建完成之后,判断组件是否需要增强
          • 是切面通知方法,包装成增强器Advisor给业务逻辑组件创建一个代理对象cglib
    • 调用目标方法
      • 代理对象执行目标方法
      • CglibAopProxy.intercept();
        • 得到目标方法的拦截器链 由增强器包装成拦截器MethodInterceptor
        • 利用拦截器的链式机制,依次进入每个拦截器进行执行
        • 正常执行 前置通知->目标方法->后置通知->返回通知
        • 异常执行: 前置通知 -> 目标方法 -> 后置通知 -> 异常通知
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值