Spring之AOP中代理对象创建时机

本文详细介绍了Spring AOP中代理对象的创建时机,从Bean的创建流程出发,分析了AbstractAutowireCapableBeanFactory的doCreateBean方法,揭示了动态代理对象的生成过程。同时,文章讨论了循环依赖的处理,解释了为何需要三级缓存来确保AOP在循环依赖中的正确应用。接着,详细探讨了AOP责任链的顺序,包括Advisor的排序逻辑,以及如何确定增强的执行顺序。最后,指出了AOP代理可能失效的情况,如在同一个类内部调用方法时,未通过代理对象调用导致AOP失效,并给出了修复方案。
部署运行你感兴趣的模型镜像

目录

1. 前言

2.动态代理对象创建的时机

3.循环依赖

4.AOP责任链的先后顺序

5.AOP代理失效原因


1. 前言

上一篇文章已经讲解过AOP责任链的实现原理(Spring之AOP的实现),这一篇文章主要讲解AOP中代理对象创建的时机,普通的IOC对象的创建流程见:Spring依赖注入(DI)之注解形式

2.动态代理对象创建的时机

我们回到Bean的创建过程,主要看AbstractAutowireCapableBeanFactory的doCreateBean方法

	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);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
        //省略部分代码

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
            //初始化bean
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			
		}
        //省略部分代码

		return exposedObject;
	}

主要是看initializeBean方法

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		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;
	}

AbstractAutowireCapableBeanFactory中的applyBeanPostProcessorsAfterInitialization方法,如下:

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
            //调用其postProcessAfterInitialization
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

这里会有AnnotationAwareAspectJAutoProxyCreator它是专门用于生成AOP代理对象的处理器

但是AnnotationAwareAspectJAutoProxyCreator中并没有postProcessAfterInitialization方法,而是它的父父父类AbstractAutoProxyCreator中实现的,我们看看这个方法:

	@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;
	}

调用wrapIfNecessary方法去判断是需要创建代理对象

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
        //获得是否有增强
		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;
	}

调用了getAdvicesAndAdvisorsForBean方法先获取是否有增强,我们这里是有做around增强,我们看看这个方法:

	@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();
	}

调用了findEligibleAdvisors方法获取是否有增强

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

这里调用的是findCandidateAdvisors方法

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

这个时候aspectJAdvisorsBuilder其实就是我们的LogAspect,buildAspectJAdvisors方法如下:

	public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;
        
        //省略部分代码
		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
            //获得的是logAround
			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;
	}

所以这里获得的是LogAspect中的logAround

这个时候回到了AbstractAdvisorAutoProxyCreator的findEligibleAdvisors方法中,会继续调用extendAdvisors方法,如下:

	@Override
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

看,惊喜不,看方法名业知道是要在代理链上增加一个特殊的advisor,我们来看看这个方法:

	public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
		// Don't add advisors to an empty list; may indicate that proxying is just not required
		if (!advisors.isEmpty()) {
			boolean foundAspectJAdvice = false;
			for (Advisor advisor : advisors) {
				// Be careful not to get the Advice without a guard, as this might eagerly
				// instantiate a non-singleton AspectJ aspect...
				if (isAspectJAdvice(advisor)) {
					foundAspectJAdvice = true;
					break;
				}
			}
			if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
                //把ExposeInvocationInterceptor增加到第一个
				advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
				return true;
			}
		}
		return false;
	}

看我们往advisors中增加了 ExposeInvocationInterceptor对象,放入到第一个元素,这个时候chain一共是有2个元素,如下所示:

我们再回到findEligibleAdvisors方法,增加了ExposeInvocationInterceptor之后,会调用sortAdvisors方法进行拦截器的排序,这里的排序涉及到责任链的顺序问题,先不展开,后面会详细讲到,这里只要知道排序后ExposeInvocationInterceptor会在第一个,然后就返回了Advisor列表,这时候只有两个元素。

我们就回到了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();
	}

如果增强列表为空,则返回一个null,表示不需要进行代理。这里我们知道返回的是有2个增强的持有增强列表。

然后我们再回到AbstractAutoProxyCreator的 wrapIfNecessary方法:

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		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;
	}

我们知道,我们获取到特定的增强拦截器不为DO_NOT_PROXY,则会调用createProxy方法去创建代理对象proxy,最终则返回这个代理对象。我们来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()) {
			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);
		}
        //创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

我们主要看最后一行代码,getProxy方法得到代理对象

	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

我们先看createAopProxy()方法,这个就是创建一个AopProxy对象,然后去调用它的getProxy方法得到代理对象,createAopProxy方法如下:

	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

这里的getAopProxyFactory获取到的是DefaultAopProxyFactory对象,我们来看看它的createAopProxy方法

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        //optimize为true或者proxyTargetClass为ture或者是没有实现
		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 {
            //使用jdk动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

可以看到,根据不同的规则去选择使用JDK动态代理还是使用CGLIB动态代理,因为我们这里本身有实现接口,且proxy-target-class: false设置为false,则使用的是JDK动态代理,即生成了JdkDynamicAopProxy对象。

然后需要调用其getProxy方法

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

可以看到,这里是调用了Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);方法去创建代理对象,需要注意的是第三个参数,传递的是this,因为JdkDynamicAopProxy本身实现了InvocationHandler接口,这就是上一章中讲到的Spring之AOP的实现_旭日的芬芳-优快云博客,为什么在目标方法调用之前会先回调JdkDynamicAopProxy的invoke方法。

如果是CGLIB的动态代理呢?我们来看看CglibAopProxy中getProxy方法

	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
		}

		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
            //得到callback回调
			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
            //创建代理对象
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

我们先看getCallbacks方法,这个方法里会包装拦截器,如下:

	private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
		// Parameters used for optimization choices...
		boolean exposeProxy = this.advised.isExposeProxy();
		boolean isFrozen = this.advised.isFrozen();
		boolean isStatic = this.advised.getTargetSource().isStatic();

		// Choose an "aop" interceptor (used for AOP calls).
		Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

		// Choose a "straight to target" interceptor. (used for calls that are
		// unadvised but can return this). May be required to expose the proxy.
		Callback targetInterceptor;
		if (exposeProxy) {
			targetInterceptor = (isStatic ?
					new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
		}
		else {
			targetInterceptor = (isStatic ?
					new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
		}

		// Choose a "direct to target" dispatcher (used for
		// unadvised calls to static targets that cannot return this).
		Callback targetDispatcher = (isStatic ?
				new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

		Callback[] mainCallbacks = new Callback[] {
                //AOP的拦截器
				aopInterceptor,  // for normal advice
				targetInterceptor,  // invoke target without considering advice, if optimized
				new SerializableNoOp(),  // no override for methods mapped to this
				targetDispatcher, this.advisedDispatcher,
				new EqualsInterceptor(this.advised),
				new HashCodeInterceptor(this.advised)
		};

		Callback[] callbacks;

		// If the target is a static one and the advice chain is frozen,
		// then we can make some optimizations by sending the AOP calls
		// direct to the target using the fixed chain for that method.
		if (isStatic && isFrozen) {
			Method[] methods = rootClass.getMethods();
			Callback[] fixedCallbacks = new Callback[methods.length];
			this.fixedInterceptorMap = new HashMap<>(methods.length);

			// TODO: small memory optimization here (can skip creation for methods with no advice)
			for (int x = 0; x < methods.length; x++) {
				Method method = methods[x];
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
				fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
						chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
				this.fixedInterceptorMap.put(method, x);
			}

			// Now copy both the callbacks from mainCallbacks
			// and fixedCallbacks into the callbacks array.
			callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
			System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
			System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
			this.fixedInterceptorOffset = mainCallbacks.length;
		}
		else {
			callbacks = mainCallbacks;
		}
		return callbacks;
	}

我们主要是关心下面这个拦截器,它是用于普通的aop增强的拦截

Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

这个对象不就是上一章中我们讲到的CGLIB动态实现中的回调类么?在获取到拦截器后,再调用了createProxyClassAndInstance方法去创建代理类。方法如下:

	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		enhancer.setInterceptDuringConstruction(false);
		enhancer.setCallbacks(callbacks);
		return (this.constructorArgs != null && this.constructorArgTypes != null ?
				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
				enhancer.create());
	}

可以看到,就是通过Enhancer的setCallback去设置回调,并调用它的create方法去创建代理对象。

这个时候,代理对象就创建出来了。我们再回到AbstractAutoProxyCreator的wrapIfNecessary方法,然后一步一步返回这个代理对象就回到了AbstractAutowireCapableBeanFactory的doCreateBean方法

exposedObject = initializeBean(beanName, exposedObject, mbd);

这个时候,exposedObject就是一个代理对象了,我们继续往下看,会调用addSingleton方法,把创建的代理对象放入到内存缓存singletonObjects中

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

这样,IOC容器就帮我们创建了一个代理对象,并存入到了singletonObjects中,它的key是AOPTestController,它的值是一个通过JDK动态代理生成的代理对象。如下:

3.循环依赖

我们在上一章Spring依赖注入(DI)之注解形式_旭日的芬芳-优快云博客最后有讲到IOC循环依赖的问题,有用到三级缓存,但是为什么是三级缓存而不是两级缓存呢?(1个半成品的bean,1成品的bean)

我们先回顾下之前的三级缓存:

//一级缓存,成品bean
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

//二级缓存,半成品bean
Map<String, Object> earlySingletonObjects = new HashMap<>(16);

//三级缓存, bean工厂
Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

其实,如果不考虑AOP的机制,通过二级缓存是可以解决循环依赖的问题的,如下:

可以看到,只要我们在创建a以后,把这个半成品放入二级缓存中,再在给b属性a复制时,从二级缓存中获取到a,就能完成b的创建,进而完成a的创建。

但如果我们a对象是一个代理对象,这个时候机制就不一样了,当给b属性赋值时,理论上是需要给它赋值一个a的代理对象,而从二级缓存中获取到的是a对象本身,这样就起不到代理作用了。

这也就是三级缓存的意义,如下图:

也就是完成A对象实例化后,把A的Bean工厂放到三级缓存中,当需要为b的属性a赋值时,是从三级缓存中拿到A的Bean工厂,创建A的代理对象,把A的代理对象放入到二级缓存中,并返回用于初始化b中的a属性。

所以,三级缓存的作用就是解决AOP中的循环依赖,把生成代理对象的过程提前了。

4.AOP责任链的先后顺序

再回到findEligibleAdvisors方法,增加了ExposeInvocationInterceptor之后,会调用sortAdvisors方法进行拦截器的排序,而这个方法是由它的子类AspectJAwareAdvisorAutoProxyCreator来实现的,我们来看看这个方法:

	@Override
	@SuppressWarnings("unchecked")
	protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
		List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
		for (Advisor element : advisors) {
			partiallyComparableAdvisors.add(
					new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
		}
		List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
		if (sorted != null) {
			List<Advisor> result = new ArrayList<>(advisors.size());
			for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
				result.add(pcAdvisor.getAdvisor());
			}
			return result;
		}
		else {
			return super.sortAdvisors(advisors);
		}
	}

这里是使用AspectJPrecedenceComparator对象来创建了一个PartiallyComparableAdvisorHolder对象来进行比较,我们来看看这个比较器的compare方法:

	@Override
	public int compare(Advisor o1, Advisor o2) {
		int advisorPrecedence = this.advisorComparator.compare(o1, o2);
		if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
			advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
		}
		return advisorPrecedence;
	}

可以看到,先是调用advisorComparator的compare方法进行比较,如果比较出来是相同的优先级且声明在相同的切面里,则调用comparePrecedenceWithinAspect中继续比较。

我们先看advisorComparator的compare,advisorComparator是一个AnnotationAwareOrderComparator对象,但它并没有实现compare方法,而需要看它的父类OrderComparator,我来看看该方法

    public int compare(@Nullable Object o1, @Nullable Object o2) {
        return this.doCompare(o1, o2, (OrderComparator.OrderSourceProvider)null);
    }

    private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {
        boolean p1 = o1 instanceof PriorityOrdered;
        boolean p2 = o2 instanceof PriorityOrdered;
        if (p1 && !p2) {
            return -1;
        } else if (p2 && !p1) {
            return 1;
        } else {
            int i1 = this.getOrder(o1, sourceProvider);
            int i2 = this.getOrder(o2, sourceProvider);
            return Integer.compare(i1, i2);
        }
    }

这里会先判断比较的对象是否实现PriorityOrdered接口,这里都没有实现,则会分别调用getOrder方法去获取order的值,

	private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
		Integer order = null;
		if (obj != null && sourceProvider != null) {
			Object orderSource = sourceProvider.getOrderSource(obj);
			if (orderSource != null) {
				if (orderSource.getClass().isArray()) {
					Object[] sources = ObjectUtils.toObjectArray(orderSource);
					for (Object source : sources) {
						order = findOrder(source);
						if (order != null) {
							break;
						}
					}
				}
				else {
					order = findOrder(orderSource);
				}
			}
		}
		return (order != null ? order : getOrder(obj));
	}

这里会调用getOrder方法

	protected int getOrder(@Nullable Object obj) {
		if (obj != null) {
			Integer order = findOrder(obj);
			if (order != null) {
				return order;
			}
		}
		return Ordered.LOWEST_PRECEDENCE;
	}

而在getOrder方法中会调用findOrder方法获取order,如果没有获取到则返回最低的优先级,这里findOrder实际调用的是子类AnnotationAwareOrderComparator的findOrder方法

	@Override
	@Nullable
	protected Integer findOrder(Object obj) {
		Integer order = super.findOrder(obj);
		if (order != null) {
			return order;
		}
		return findOrderFromAnnotation(obj);
	}

这里是先调用父类的findOrder方法,如下:

    @Nullable
    protected Integer findOrder(Object obj) {
        return obj instanceof Ordered ? ((Ordered)obj).getOrder() : null;
    }

如果实现了Ordered接口,则调用getOrder得到order,如果没有则返回null,我们自定义的切面增强其实是属于InstantiationModelAwarePointcutAdvisorImpl实体,下面是它的定义:

final class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {

而AspectJPrecedenceInformation就是一个继承于Ordered的接口,定义如下:

public interface AspectJPrecedenceInformation extends Ordered {

所以我们的环绕增强,其实也是属于Ordered,所以会调用它的getOrder方法,但不管怎么样,最后会调用到OrderUtils中的getOrder方法

	public static int getOrder(Class<?> type, int defaultOrder) {
		Integer order = getOrder(type);
		return (order != null ? order : defaultOrder);
	}

会先调用getOrder方法,这里返回的为null,则是给定的默认排序,这里默认的排序是Integer的最大值,因为order定义为Integer,其实这里就是最低优先级

int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

我们再回到AnnotationAwareOrderComparator的findOrder方法,这个时候order就有值了,然后我们再看ExposeInvocationInterceptor,它本身实现了PriorityOrdered(是Ordered接口的子接口)接口,并且实现了getOrder方法

	@Override
	public int getOrder() {
		return PriorityOrdered.HIGHEST_PRECEDENCE + 1;
	}

而HIGHEST_PRECEDENCE是在Ordered中定义的,表示最高优先级

public interface Ordered {
    int HIGHEST_PRECEDENCE = -2147483648;
    int LOWEST_PRECEDENCE = 2147483647;

    int getOrder();
}

这也是为什么ExposeInvocationInterceptor会排序到最前面的原因,我们回到AspectJPrecedenceComparator的compare方法

	@Override
	public int compare(Advisor o1, Advisor o2) {
		int advisorPrecedence = this.advisorComparator.compare(o1, o2);
		if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
			advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
		}
		return advisorPrecedence;
	}

这个时候advisorPrecedence=1,即环绕增强的优先级更低,如下图所示:

这个如果是两个没有实现Ordered接口或者实现了Ordered接口但是返回的order一致的情况下,

比如我们自己定义的切面,没有实现Ordered接口,则这里返回了null,则

核心方法是在comparePrecedenceWithinAspect中,会先判断是否是后置增强,如果是后置增强,则越晚声明权限越高,否则越早声明权限越高。

是直接调用的AnnotationAwareOrderComparator.sort方法进行排序,方法如下:

    public static void sort(List<?> list) {
        if (list.size() > 1) {
            list.sort(INSTANCE);
        }

    }

这里传入的是AnnotationAwareOrderComparator的实例,我们来看看它的findOrder方法

    @Nullable
    protected Integer findOrder(Object obj) {
        Integer order = super.findOrder(obj);
        return order != null ? order : this.findOrderFromAnnotation(obj);
    }

    @Nullable
    private Integer findOrderFromAnnotation(Object obj) {
        AnnotatedElement element = obj instanceof AnnotatedElement ? (AnnotatedElement)obj : obj.getClass();
        MergedAnnotations annotations = MergedAnnotations.from((AnnotatedElement)element, SearchStrategy.TYPE_HIERARCHY);
        Integer order = OrderUtils.getOrderFromAnnotations((AnnotatedElement)element, annotations);
        return order == null && obj instanceof DecoratingProxy ? this.findOrderFromAnnotation(((DecoratingProxy)obj).getDecoratedClass()) : order;
    }

会先调用super.findOrder方法,调用的是OrderComparator的findOrder方法,下面是这个类的源码

    @Nullable
    protected Integer findOrder(Object obj) {
        return obj instanceof Ordered ? ((Ordered)obj).getOrder() : null;
    }

这里就是判断我们的切面是否实现了Ordered接口,如果实现了,则直接调用其getOrder得到排序的循序。这其实就是上一讲当中讲到的,对相同连接点的多个切面的先后顺序的实现了。

5.AOP代理失效原因

在有些情况下,AOP会失效,我们在AOPTestController中创建a、b两个方法,如下:

@RestController
@RequestMapping("aop")
@Api(tags = "测试AOP")
public class AOPTestController {


    @Log
    @PostMapping(value = "a")
    public String a() {
        return "a";
    }

    @Log
    @PostMapping(value = "b")
    public String b() {
        return "b";
    }
}

我们分别请求下a、b接口,发现的确是有日志拦截的,证明AOP是生效了的。

但是我们如果,在a方法中去调用b方法,这个时候会有b方法被调用的日志输出么?代码如下:

    @Log
    @PostMapping(value = "a")
    public String a() {
        // 手动调用b方法
        b();
        return "a";
    }

下面是运行结果

我们发现只有a方法的日志,而没有b方法的日志,这个其实不难理解,AOP的实现原理是需要生成代理对象,当我们调用业务方法时,其实是先回调了DynamicAdvisedInterceptor中的intercept方法或者JdkDynamicAopProxy的invoke方法,然后会去遍历增强,并且会去调用业务方法,但是真正调用到业务方法时,在业务方法中去调用其他方法时,没有使用代理对象,而是直接调用的被代理对象的方法,所以就不会有拦截日志,像上面的就是直接调用的AOPTestController的b方法。这样,看起来好像AOPTestController的b方法的AOP失效了,虽然它也使用了@Log注解。

那要怎么做才能让b方法也能走日志拦截呢?

根据上面的分析,其实我们也知道答案了,就是需要通过AOPTestController的代理对象来调用b方法嘛。

Spring提供了一个AopContext类,它有一个currentProxy方法可以获取到当前类的代理对象,代码如下

    @Log
    @PostMapping(value = "a")
    public String a() {
        ((AOPTestController)AopContext.currentProxy()).b();
        return "a";
    }

调用结果如下:

发现报错了,是需要设置exposeProxy,我们可以在启动的Application中增加如下注解:

@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

 这个时候,我们再调用a方法,结果如下:

可以看到,b也有拦截日志,并且是跟我们方法执行的顺序一致:a方法参数-> b方法参数->b方法返回->a方法返回

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

<think>嗯,用户问的是Spring框架中AOP动态代理对象创建阶段。我之前已经回答过类似的问题,但现在需要结合提供的引用内容来更详细地分析。首先,用户可能是在准备面试或者深入学习Spring的工作原理,特别是AOP的机制。用户可能已经知道AOP的基本概念,但想深入了解其生命周期中的具体步骤。 根据用户提供的引用,引用[3]提到动态代理是在Bean生命周期的postProcessAfterInitialization阶段创建的,也就是初始化之后。而引用[2]中有人提问为什么Spring在属性设置完成后才生成代理对象,而不是一开始就生成。这可能是用户想确认代理对象创建时机,以及背后的原因。 我需要整理Spring Bean的生命周期,然后指出AOP代理创建的具体阶段。根据引用[3],创建代理是在BeanPostProcessor的postProcessAfterInitialization方法中进行的,而BeanPostProcessor的两个方法分别在初始化前后执行。因此,动态代理的创建应该是在Bean初始化完成之后,属性注入之后。这解释了为什么代理对象是在属性设置之后生成,因为如果提前生成代理,可能无法正确处理依赖注入,导致属性未被正确设置。 另外,引用[4]提到CGLIB不能代理private方法,因为它是通过继承实现的,而私有方法无法被覆盖。这可能与用户的问题相关,因为动态代理的方式(JDK还是CGLIB)会影响代理对象创建阶段,但用户的问题主要关注的是创建时机,而不是具体代理方式的选择。 还需要考虑用户提到的其他引用,比如引用[1]中关于Spring AOP原理和执行流程的总结,这可能涉及到整个AOP的处理流程,包括Advisor的扫描和代理的生成步骤。因此,在回答中需要将创建阶段分解为几个步骤,如Advisor扫描、代理决策、代理生成时机等,并结合Bean的生命周期阶段。 用户可能存在的深层疑问是:为什么Spring选择在这个阶段创建代理?是否存在性能或设计上的考量?根据引用[2],如果在属性注入前创建代理,可能会导致代理对象未正确初始化,依赖注入出现问题。因此,Spring选择在Bean完全初始化后创建代理,确保所有依赖已经注入,避免潜在的问题。 总结来说,回答需要明确以下几点: 1. 动态代理的创建阶段是在Bean初始化后的postProcessAfterInitialization阶段。 2. 具体由AnnotationAwareAspectJAutoProxyCreator处理。 3. 创建代理的步骤包括检查是否需要代理,选择代理方式(JDK或CGLIB),生成代理对象。 4. 解释为什么不在属性注入前创建代理,以确保依赖正确注入。 此外,用户可能希望了解整个流程中的关键类和接口,如BeanPostProcessor、AbstractAutoProxyCreator等,这些在引用[3]和之前的回答中都有提到,需要整合到当前回答中,确保结构清晰,符合用户的需求。</think>#### Spring AOP 动态代理对象创建阶段详解 --- ### **核心结论** Spring AOP 的动态代理对象创建发生在 **Bean 初始化完成之后、正式交付使用之前**,具体由 `AnnotationAwareAspectJAutoProxyCreator`(继承自 `AbstractAutoProxyCreator`)在 `BeanPostProcessor.postProcessAfterInitialization` 方法中完成[^3][^4]。 --- ### **详细流程拆解** #### **1. 代理对象创建的触发时机** 在 Spring Bean 的生命周期中,代理对象的生成位于以下阶段: ``` 实例化 -> 属性注入 -> Aware 接口回调 -> BeanPostProcessor.postProcessBeforeInitialization -> 自定义初始化(@PostConstruct / InitializingBean) -> **BeanPostProcessor.postProcessAfterInitialization(动态代理在此处生成)** -> 代理对象加入容器缓存 -> 客户端使用 ``` #### **2. 动态代理生成的关键步骤** 1. **Advisor 的扫描与收集** Spring 在容器启动时通过 `AspectJAutoProxyRegistrar` 扫描所有标记了 `@Aspect` 的类,将其转换为 `Advisor`(封装 Pointcut 和 Advice),为后续代理决策提供依据[^4]。 2. **代理决策与生成时机** 在 `postProcessAfterInitialization` 方法中,`AbstractAutoProxyCreator` 会检查当前 Bean: - 是否为基础设施类(如 `Advisor` 自身) - 是否匹配已注册的 `Advisor` 的 Pointcut 表达式 - **若需要代理**,则根据目标类是否实现接口,选择 **JDK 动态代理** 或 **CGLIB 代理** 生成代理对象[^3][^4]。 3. **代理生成逻辑** - **JDK 动态代理**:基于接口,通过 `InvocationHandler` 实现方法拦截(要求目标类实现接口)。 - **CGLIB 代理**:基于继承,生成目标类的子类并重写方法(若目标类无接口或方法为 `final`/`private` 则无法代理)[^4]。 #### **3. 为何不在属性注入前生成代理?** Spring 选择在 **属性注入完成且 Bean 初始化后** 生成代理,是为了保证: - **依赖注入的完整性**:若代理过早生成,可能导致注入的属性未完成设置(例如通过 `@Autowired` 注入的依赖)[^2]。 - **初始化逻辑的执行**:自定义初始化方法(如 `@PostConstruct`)需在原始对象上执行,而非代理对象。 --- ### **代码示例与验证** ```java // 验证代理生成阶段的示例 Bean @Service public class UserService { @Autowired private RoleRepository roleRepository; // 依赖注入需在代理前完成 public void createUser() { System.out.println("Creating user..."); } } // 通过调试断点观察代理对象生成时机 public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); System.out.println(userService.getClass()); // 输出代理类:com.sun.proxy.$ProxyXX 或 UserService$$EnhancerBySpringCGLIB } ``` --- ### **常见问题延伸** 1. **为什么 CGLIB 无法代理 `private` 方法?** CGLIB 通过生成子类实现代理,而子类无法重写父类的 `private` 方法,因此无法拦截调用。 2. **如何强制使用 CGLIB 代理?** 在 `@EnableAspectJAutoProxy` 中设置 `proxyTargetClass=true`: ```java @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig {} ``` 3. **代理对象对循环依赖的影响** 若 Bean 之间存在循环依赖,且涉及 AOP 代理,Spring 会通过 **三级缓存** 机制提前暴露原始对象完成依赖注入,再生成最终代理对象。 --- ### **性能与设计权衡** - **代理延迟生成**:避免无意义的代理创建(仅对匹配 Pointcut 的 Bean 生成代理)。 - **缓存机制**:代理对象生成后会被缓存,避免重复创建开销[^3]。 --- ### **相关问题** 1. 如何验证某个 Bean 是否被 AOP 代理? 2. Spring 如何处理同时需要 JDK 和 CGLIB 代理的复杂场景? 3. 动态代理对 Bean 生命周期回调(如 `@PreDestroy`)有何影响?
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值