SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析

文章目录

  • 系列文档索引
  • 六、@EnableAspectJAutoProxy源码分析
    • 1、AnnotationAwareAspectJAutoProxyCreator源码
      • (1)wrapIfNecessary方法
      • (2)createProxy
    • 2、getAdvicesAndAdvisorsForBean查找所有Advisor
      • (1)findCandidateAdvisors查找
      • (2)查找AspectJ定义的Advisor
      • (3)getAdvisors解析切面Bean
      • (4)getAdvisor:根据某个方法生成Advisor
      • (5)findAdvisorsThatCanApply进行筛选(回到最初)
      • (6)InstantiationModelAwarePointcutAdvisorImpl的getAdvice方法
    • 3、总结
      • (1)AbstractAdvisorAutoProxyCreator
      • (2)@EnableAspectJAutoProxy
      • (3)流程图

系列文档索引

SpringAOP从入门到源码分析大全(一)熟悉动态代理
SpringAOP从入门到源码分析大全(二)熟悉ProxyFactory
SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析
SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析
SpringAOP从入门到源码分析大全(五)手写一个编程式AOP

六、@EnableAspectJAutoProxy源码分析

1、AnnotationAwareAspectJAutoProxyCreator源码

使用@EnableAspectJAutoProxy,会引入一个AspectJAutoProxyRegistrar的Bean,这个Bean会注册AnnotationAwareAspectJAutoProxyCreator为BeanDefinition。

AnnotationAwareAspectJAutoProxyCreator集成了AbstractAutoProxyCreator,AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor,在postProcessAfterInitialization方法中,会进行AOP。

注意!该方法中,如果有循环依赖的话,会对Bean提前AOP,循环依赖不是此处讨论的重点。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

(1)wrapIfNecessary方法

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	// advisedBeans表示已经判断过了的Bean,false表示不需要再进行AOP了(循环依赖会提前AOP)
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	// 当前正在创建的Bean不用进行AOP,比如切面Bean
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	// 判断当前bean是否存在匹配的advice,如果存在则要生成一个代理对象
	// 此处根据类以及类中的方法区匹配到Interceptor(也就是Advice),然后生成代理对象,代理对象在执行的时候,还会根据当前参数进行匹配
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		// advisedBeans记录了某个Bean已经进行AOP了
		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;
}

(2)createProxy

这就是我们熟悉的,使用ProxyFactory,进行代理对象的创建了。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#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()) {
		// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
			// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
			for (Class<?> ifc : beanClass.getInterfaces()) {
				proxyFactory.addInterface(ifc);
			}
		}
	}
	else {
		// No proxyTargetClass flag enforced, let's apply our default checks...
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
		classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
	}
	return proxyFactory.getProxy(classLoader);
}

2、getAdvicesAndAdvisorsForBean查找所有Advisor

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 找到所有的Advisor
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// 进行筛选
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	// 对Advisor进行排序,按Ordered接口、@Order注解进行排序
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

(1)findCandidateAdvisors查找

又回到了AnnotationAwareAspectJAutoProxyCreator

//  org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	// 先找到所有Advisor类型的Bean对象,是父类的方法
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	// 再从所有切面中解析得到Advisor对象
	if (this.aspectJAdvisorsBuilder != null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}

(2)查找AspectJ定义的Advisor

// org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = this.aspectBeanNames;

	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new ArrayList<>();
				aspectNames = new ArrayList<>();
				// 把所有的Bean拿出来遍历,判断某个bean的类型是否是Aspect
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {
					if (!isEligibleBean(beanName)) {
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					Class<?> beanType = this.beanFactory.getType(beanName, false);
					if (beanType == null) {
						continue;
					}
					//  (hasAspectAnnotation(clazz) && !compiledByAjc(clazz)); 是否有@Aspect
					if (this.advisorFactory.isAspect(beanType)) {
						aspectNames.add(beanName);
						// 切面的注解信息
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						// 如果@Aspect不是perthis、pertarget,那么一个切面只会生成一个对象(单例)
						// 并且会将该切面中所对应的Advisor对象进行缓存
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							// 利用BeanFactoryAspectInstanceFactory来解析Aspect
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							if (this.beanFactory.isSingleton(beanName)) {
								// 缓存切面所对应的所有Advisor对象
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
								this.aspectFactoryCache.put(beanName, factory);
							}
							advisors.addAll(classAdvisors);
						}
						else {
							// Per target or per this.
							if (this.beanFactory.isSingleton(beanName)) {
								throw new IllegalArgumentException("Bean with name '" + beanName +
										"' is a singleton, but aspect instantiation model is not singleton");
							}
							MetadataAwareAspectInstanceFactory factory =
									new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
							this.aspectFactoryCache.put(beanName, factory);
							advisors.addAll(this.advisorFactory.getAdvisors(factory));
						}
					}
				}
				this.aspectBeanNames = aspectNames;
				return advisors;
			}
		}
	}

	if (aspectNames.isEmpty()) {
		return Collections.emptyList();
	}
	List<Advisor> advisors = new ArrayList<>();
	for (String aspectName : aspectNames) {
		List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
		if (cachedAdvisors != null) {
			advisors.addAll(cachedAdvisors);
		}
		else {
			MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
			advisors.addAll(this.advisorFactory.getAdvisors(factory));
		}
	}
	return advisors;
}

(3)getAdvisors解析切面Bean

// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
	validate(aspectClass);

	// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
	// so that it will only instantiate once.
	// 保证切面Bean对象只会实例化一次
	// 一定要注意,这里是直接new出来一个LazySingletonAspectInstanceFactoryDecorator
	// 也就是OrderService这个Bean在执行生命周期过程中,会需要判断要不要进行AOP,就会找到切面
	// 发现切面如果是pertarget或perthis,那么就会进入到这个方法,就会new LazySingletonAspectInstanceFactoryDecorator
	MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

	List<Advisor> advisors = new ArrayList<>();
	// 获取切面类中没有加@Pointcut的方法,并进行排序,进行遍历生成Advisor 
	for (Method method : getAdvisorMethods(aspectClass)) {
		// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
		// to getAdvisor(...) to represent the "current position" in the declared methods list.
		// However, since Java 7 the "current position" is not valid since the JDK no longer
		// returns declared methods in the order in which they are declared in the source code.
		// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
		// discovered via reflection in order to support reliable advice ordering across JVM launches.
		// Specifically, a value of 0 aligns with the default value used in
		// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	// If it's a per target aspect, emit the dummy instantiating aspect.
	if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
		advisors.add(0, instantiationAdvisor);
	}

	// Find introduction fields.
	for (Field field : aspectClass.getDeclaredFields()) {
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}

(4)getAdvisor:根据某个方法生成Advisor

// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
		int declarationOrderInAspect, String aspectName) {

	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

	// 拿到当前方法所对应的Pointcut对象,但是注意:如果当前方法上这么写@After("pointcut()")
	AspectJExpressionPointcut expressionPointcut = getPointcut(
			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}

	// expressionPointcut 是Pointcut
	// candidateAdviceMethod承载了advice
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

(5)findAdvisorsThatCanApply进行筛选(回到最初)

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}
	finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

// org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new ArrayList<>();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
		// canApply就是调用Pointcut的match方法进行匹配,先根据类再根据方法
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

// org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	if (!pc.getClassFilter().matches(targetClass)) { // 匹配类
		return false;
	}

	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}

	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	// 至少有一个方法与方法匹配器匹配
	for (Class<?> clazz : classes) {
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		for (Method method : methods) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

(6)InstantiationModelAwarePointcutAdvisorImpl的getAdvice方法

// org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#getAdvice
@Override
public synchronized Advice getAdvice() {
	if (this.instantiatedAdvice == null) {
		// 根据方法生成Advice
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
	}
	return this.instantiatedAdvice;
}

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
	Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
			this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
	return (advice != null ? advice : EMPTY_ADVICE);
}
/// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	validate(candidateAspectClass);
	// 拿到方法上的注解信息
	AspectJAnnotation<?> aspectJAnnotation =
			AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
		return null;
	}

	// If we get here, we know we have an AspectJ method.
	// Check that it's an AspectJ-annotated class
	if (!isAspect(candidateAspectClass)) {
		throw new AopConfigException("Advice must be declared inside an aspect type: " +
				"Offending method '" + candidateAdviceMethod + "' in class [" +
				candidateAspectClass.getName() + "]");
	}

	if (logger.isDebugEnabled()) {
		logger.debug("Found AspectJ method: " + candidateAdviceMethod);
	}

	AbstractAspectJAdvice springAdvice;
	// 挨个判断,进行挨个对应
	switch (aspectJAnnotation.getAnnotationType()) {
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		default:
			throw new UnsupportedOperationException(
					"Unsupported advice type on method: " + candidateAdviceMethod);
	}

	// Now to configure the advice...
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrder);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();

	return springAdvice;
}

在这里插入图片描述
所以,每个注解对应了一个MethodInterceptor

@Before对应的是AspectJMethodBeforeAdvice,在进行动态代理时会把AspectJMethodBeforeAdvice转成MethodBeforeAdviceInterceptor
先执行advice对应的方法
再执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法

@After对应的是AspectJAfterAdvice,直接实现了MethodInterceptor
先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
再执行advice对应的方法

@Around对应的是AspectJAroundAdvice,直接实现了MethodInterceptor
直接执行advice对应的方法,由@Around自己决定要不要继续往后面调用

@AfterThrowing对应的是AspectJAfterThrowingAdvice,直接实现了MethodInterceptor
先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
如果上面抛了Throwable,那么则会执行advice对应的方法

@AfterReturning对应的是AspectJAfterReturningAdvice,在进行动态代理时会把AspectJAfterReturningAdvice转成AfterReturningAdviceInterceptor
先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
执行上面的方法后得到最终的方法的返回值
再执行Advice对应的方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、总结

(1)AbstractAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator的父类是AbstractAdvisorAutoProxyCreator。

AbstractAdvisorAutoProxyCreator非常强大以及重要,只要Spring容器中存在这个类型的Bean,就相当于开启了AOP,AbstractAdvisorAutoProxyCreator实际上就是一个BeanPostProcessor,所以在创建某个Bean时,就会进入到它对应的生命周期方法中,比如:在某个Bean初始化之后,会调用wrapIfNecessary()方法进行AOP,底层逻辑是,AbstractAdvisorAutoProxyCreator会找到所有的Advisor,然后判断当前这个Bean是否存在某个Advisor与之匹配(根据Pointcut),如果匹配就表示当前这个Bean有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。

(2)@EnableAspectJAutoProxy

这个注解主要就是往Spring容器中添加了一个AnnotationAwareAspectJAutoProxyCreator类型的Bean。
在这里插入图片描述
AspectJAwareAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,重写了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator只能找到所有Advisor类型的Bean对象,但是AspectJAwareAdvisorAutoProxyCreator除开可以找到所有Advisor类型的Bean对象,还能把@Aspect注解所标注的Bean中的@Before等注解及方法进行解析,并生成对应的Advisor对象。

所以,我们可以理解@EnableAspectJAutoProxy,其实就是像Spring容器中添加了一个AbstractAdvisorAutoProxyCreator类型的Bean,从而开启了AOP,并且还会解析@Before等注解生成Advisor。

(3)流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/563392.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能入门(一):基于Pytorch的手写数字识别模型

前言&#xff1a; 因为还在上学&#xff0c;时间不太够用&#xff0c;很多内容写到后面心有余力不足&#xff0c;未来有时间我会慢慢补充。人工智能的知识涉猎范围广又杂乱无章&#xff0c;啃书或上课学到的知识往往很早就过时了或者离实际的项目无关。所以&#xff0c;我很希…

安装mmsegmentation默认主分支main

安装时间2024.4.21 mmsegmentation新版本main分支&#xff08;v1.2.2&#xff09; 安装过程 conda create --name openmmlab python3.8 -y conda activate openmmlab// 很关键&#xff0c;可以避免mmcv版本问题 pip install torch1.10.1cu113 torchvision0.11.2cu113 torcha…

【力扣 Hot100 | 第七天】4.22(移动零)

文章目录 1.移动零1.1题目1.2解法&#xff1a;双指针1.2.1双指针思路1.2.2代码实现 1.移动零 1.1题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数…

[docker] volume 补充 环境变量 参数

[docker] volume 补充 & 环境变量 & 参数 这里补充一下 volume 剩下的内容&#xff0c;以及添加参数(ARG) 和 环境变量 ENV 的内容 read only volumes ❯ docker run-p 3000:80--rm--name feedback-app-v feedback:/app/feedback-v "$(pwd):/app"-v /app/…

第 394 场 LeetCode 周赛题解

A 统计特殊字母的数量 I 哈希&#xff1a;遍历然后枚举 class Solution {public:int numberOfSpecialChars(string word) {unordered_map<char, int> m;for (auto ch : word)m[ch] 1;int res 0;for (char ch a; ch < z; ch)if (m.count(ch) && m.count(A …

爬虫采集:数据提取

目录 1. 数据分类 2. JSON 2.1 json数据转换​编辑 3. 正则表达式 3.1 re模块 3.1.1 常见方法 3.1.2 单字符匹配 3.1.4 匹配开头和结尾 3.1.5 分组匹配 3.1.6 贪婪非贪婪匹配 4. Xpath 4.1 语法 4.2 查找特定节点 4.3 lxml 模块 4.3.1 安装 4.3.2 导入 4.3.3 使…

【行为型模式】命令模式

一、命令模式概述 命令模式的定义&#xff1a;将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(对象行为型) 命令模式优缺点&#xff1a; 优点&#xff1a; 1.类间解耦&#xff1a;调用者角色与接收者角色之间没有任何依…

TPG原理以及verilog实现

文章目录 一、前言二、verilog代码实现三、仿真以及结果分析 一、前言 TPG(video_test_pattern generator) 视频测试模式发生器用于产生测试数据&#xff0c;对视频数据通路测试。根据视频输出时序产生相应的图像数据 二、verilog代码实现 timescale 1ns / 1nsmodule tpg ( i…

鸿蒙入门10-CheckBoxGroup组件

复选框群组 用于控制多个复选框全选或者不全选状态 参数 参数形式 &#xff1a; CheckboxGroup( options?: { group?: string } ) 创建复选框群组&#xff0c;可以用于控制群组内的 CheckBox 成员 全选 或者 不全选 相同 group 的 CheckBox 和 CheckBoxGroup 为同一群组 参…

Python turtle海龟绘制美国队长盾牌

使用Python中的turtle模块绘制美队盾牌 具体思路如下&#xff1a; 导入海龟库第1个圆&#xff1a;半径 200&#xff0c;红色填充第2个圆&#xff1a;半径 150&#xff0c;白色填充第3个圆&#xff1a;半径 100&#xff0c;红色填充第4个圆&#xff1a;半径 50&#xff0c;蓝色…

摩科智能协办“提高不动产登记质量,促进优化营商环境培训会”

为深入落实国家和自治区自然资源工作会议精神&#xff0c;加强不动产登记队伍作风常态化建设&#xff0c;提高不动产登记质量&#xff0c;促进优化营商环境&#xff0c;学习先进地区工作经验。2024年4月19日&#xff0c;“提高不动产登记质量 促进优化营商环境培训会”在浙江省…

在PostgreSQL中如何实现分区表以提高查询效率和管理大型表?

文章目录 解决方案1. 确定分区键2. 创建分区表3. 数据插入与查询4. 维护与管理 示例代码1. 创建父表和子表2. 插入数据3. 查询数据 总结 随着数据量的增长&#xff0c;单一的大型表可能会遇到性能瓶颈和管理难题。PostgreSQL的分区表功能允许我们将一个大型表分割成多个较小的、…

windows驱动开发-内存概述

“90%的程序问题都是由内存引起的&#xff0c;剩下的10%是使用内存引起的&#xff01;”这是一句非常经典的论证&#xff0c;实际上&#xff0c;在程序开发中&#xff0c;内存问题就是最大的问题&#xff0c;没有之一。 现代的计算机体系中&#xff0c;内存承载了太多的功能&a…

HttpServlet,ServletContext,Listener它仨的故事

1.HttpServlet。 听起来是不是感觉像是个上古词汇&#xff0c;是不是没有阅读下去的兴趣了&#xff1f;Tomcat知道吧&#xff0c;它就是一个servlet容器&#xff0c;当用户向服务器发送一个HTTP请求时&#xff0c;Servlet容器&#xff08;如Tomcat&#xff09;会根据其配置找到…

Vue项目实现懒加载——自用笔记

熟悉指令语法&#xff1a; <template><HomePanel title"人气推荐" sub-title"人气爆款 不容错过"><ul class"goods-list"><li v-for"item in hotList" :key"item.id"><RouterLink to"/&qu…

嵌入式Linux开发

(17 封私信 / 1 条消息) 嵌入式Linux应用 - 搜索结果 - 知乎 (zhihu.com)

【面试】输出设备-①-Tableau入门

感谢大佬 举个栗子&#xff01;Tableau 技巧&#xff08;266&#xff09;&#xff1a;学做双向圆角条形图-CSDN博客 感谢W3Cschool Tableau 概述_w3cschool 感谢Tableau 官方社区 Discover | Tableau Public 1.目标和计划 近期公司需要进行数据大屏的制作&#xff0c;调研了一下…

【大语言模型LLM】-大语言模型乐园,高效办公不迷路!

&#x1f525;博客主页&#xff1a;西瓜WiFi &#x1f3a5;系列专栏&#xff1a;《大语言模型》 ❤️感谢大家点赞&#x1f44d; 收藏⭐ 评论⭐ &#x1f3a5;大语言模型LLM基础-系列文章&#xff1a; 【大语言模型LLM】-大语言模型如何编写Prompt? 【大语言模型LLM】-如何…

Pytorch第一部分数据模块

数据划分&#xff1a; 从数据集中将数据划分为训练集&#xff0c;测试集&#xff0c;验证集 # -*- coding: utf-8 -*- """ # file name : 1_split_dataset.py # author : tingsongyu # date : 2019-09-07 10:08:00 # brief : 将数据集划分为训…

Gamba:将高斯溅射与Mamba结合用于单视图3D重建

Gamba: Marry Gaussian Splatting with Mamba for Single-View 3D Reconstruction Gamba&#xff1a;将高斯溅射与Mamba结合用于单视图3D重建 Qiuhong Shen11  Xuanyu Yi31 Zike Wu31  Pan Zhou2,42 Hanwang Zhang3,5 沈秋红 1 易轩宇 3 吴子可 3 潘周 2,4 2 张汉旺 3,5Shu…