07_spring对于单例bean的aop代理实现

本文详细阐述了Spring框架中单例Bean如何在AOP(面向切面编程)中实现动态代理,涉及JDK动态代理和CGlib动态代理两种方式,并介绍了关键类AbstractAutoProxyCreator的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例bean在spring中aop实现过程。
动态代理的两种方式:
①基于JDK的动态代理
基于接口的动态代理,用到的类是Proxy的newProxyInstance静态方法创建,要求被代理对象至少实现一个接口,如果没有,则不能创建代理对象。
②基于cglib的动态代理
要导入cglib第三方库,使用的类是Enhancer的create静态方法创建,要求被代理类不能是最终类,即不能用final修饰,如String类。
源码解析:
核心类
AbstractAutoProxyCreator
为什么是这个类
我们会使用@EnableAspectJAutoProxy注解来开启aop
源码实现

public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		// 注册一个AnnotationAwareAspectJAutoProxyCreator类型的Bean,beanName为AUTO_PROXY_CREATOR_BEAN_NAME
		//org.springframework.aop.config.internalAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 修改AnnotationAwareAspectJAutoProxyCreator中对应的属性
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

这个注解会在spring容器中初始化一个类AnnotationAwareAspectJAutoProxyCreator。他就是AbstractAutoProxyCreator 的子类。

我们再看看AbstractAutoProxyCreator 的实现。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
		}

可以看到AbstractAutoProxyCreator实现了BeanPostProcessor的子接口SmartInstantiationAwareBeanPostProcessor,那么我们可以联想到AbstractAutoProxyCreator会实现以下两个方法

	//BeanPostProcessor的前置处理器
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	//BeanPostProcessor的前置处理器
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

他们会在什么时候执行呢,如图:
在这里插入图片描述
会在bean初始化之前和初始化之后。
那么我们看到这里,再来看看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;
	}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}

		// advisedBeans表示已经判断过了的bean,false表示此bean不需要进行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;
	}

从源码可以看出代理是在bean的初始化后进行动态代理的。也可以在方法wrapIfNecessary看到createProxy方法创建代理对象。再来进入createProxy方法查看spring采用哪些方式进行代理对象的创建。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// 如果ProxyFactory的isOptimize为true,Spring认为cglib比jdk动态代理要快
		// 或者isProxyTargetClass为true,
		// 或者被代理对象没有实现接口,
		// 或者只实现了SpringProxy这个接口
		// 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理

		// 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口

		// 是不是在GraalVM虚拟机上运行
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {

			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

从源码看出spring会采用两种代理方式 基于JDK的动态代理和基于cglib的动态代理。

总结:
spring正常的单例bean的aop代理实现是在bean初始化后进行的动态代理,也可以看出spring的动态代理有两种方式,基于JDK的动态代理和基于cglib的动态代理。
但是在循环依赖中spring的代理会有所不同。我们下一章进行详细讲解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值