@Configuration的Full和Lite模式源码探究

@Configuration注解源码如下
其中有一个proxyBeanMethods属性,就是决定注册到Spring容器中的是原始Bean(Lite模式)还是代理Bean(Full模式)
该属性默认为true,也就是默认是Full模式

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
	@AliasFor(annotation = Component.class)
	String value() default "";

	boolean proxyBeanMethods() default true;
}

具体代码就不演示了,可以自己写两个Class,一个加上@Configuration,一个加上@Configuration(proxyBeanMethods = false)
然后通过BeanFactory去获取打印观察区别

@Configuration的解析处理相关的类是ConfigurationClassPostProcessor
类的部分继承关系如下
在这里插入图片描述

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}
public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

到这里至少知道ConfigurationClassPostProcessor中要实现上面两个接口的方法
现在就要知道分别是什么时候执行的

直接定位到容器启动处:AbstractApplicationContext#refresh,核心代码的入口都在这里
然后根据debug,应该在invokeBeanFactoryPostProcessors这个方法中执行两个process方法

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// ...
		try {
			// ...
			
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// ...
		}
	}
}

继续跟踪,会在PostProcessorRegistraionDelegate#invokeBeanFactoryPostProcessors中找到两个方法调用
说明是先执行的postProcessBeanDefinitionRegistry,再执行postProcessBeanFactory
在这里插入图片描述

这时回头看ConfigurationClassPostProcessor中的两个方法
先看postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}

继续跟踪,会在processConfigBeanDefinitions方法里看到以下的if else
第一个if就是检查是不是已经处理过了,从日志也能看出来,具体是获取一个属性:CONFIGURATION_CLASS_ATTRIBUTE,这个属性就是后面用来决定是Full模式还是Lite模式

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
	// ...
}

这里先说明一下,如果我们自己写了@Configuration的类,实际上是在ConfigurationClassParser#doProcessConfigurationClass方法中处理的,这个方法中也会调用ConfigurationClassUtils#checkConfigurationClassCandidate,逻辑是一样的,上面可以当作是引出ConfigurationClassUtils#checkConfigurationClassCandidate这个方法,暂且按照这个思路接着往下进行

下面主要看else逻辑,继续跟踪ConfigurationClassUtils#checkConfigurationClassCandidate方法
这里面会设置刚才if中判断的那个属性:CONFIGURATION_CLASS_ATTRIBUTE
第一个if中获取@ConfigurationproxyBeanMethods属性,如果不为false,就设置属性为:CONFIGURATION_CLASS_FULL,这就是Full模式的条件

public static boolean checkConfigurationClassCandidate(
		BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

	// ...
	
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}

	// ...

	return true;
}

对应的,else if中就是Lite模式的条件

如果config==null,再看isConfigurationCandidate方法,但是如果是标注@Configuration的类,这里config一定不为null,暂且忽略isConfigurationCandidate这个方法
也就是说,当proxyBeanMethods值为false,设置为Lite模式

到此,postProcessBeanDefinitionRegistry这个方法调用中,关于Full模式和Lite模式的设置,就完成了,就是向BeanDefinition中设置一个属性CONFIGURATION_CLASS_ATTRIBUTE,值为full或lite

abstract class ConfigurationClassUtils {

	public static final String CONFIGURATION_CLASS_FULL = "full";

	public static final String CONFIGURATION_CLASS_LITE = "lite";

	// ...
}

下面看ConfigurationClassPostProcessor中第二个调用的方法:postProcessBeanFactory
看一下这个方法注释,大概意思就是通过cglib增强

/**
 * Prepare the Configuration classes for servicing bean requests at runtime
 * by replacing them with CGLIB-enhanced subclasses.
 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	int factoryId = System.identityHashCode(beanFactory);
	if (this.factoriesPostProcessed.contains(factoryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
	}
	this.factoriesPostProcessed.add(factoryId);
	if (!this.registriesPostProcessed.contains(factoryId)) {
		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
		// Simply call processConfigurationClasses lazily at this point then.
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}

	enhanceConfigurationClasses(beanFactory);
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

enhanceConfigurationClasses这个方法中会判断之前设置的CONFIGURATION_CLASS_ATTRIBUTE属性,如果为full,就进行动态代理

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	// ...
	for (String beanName : beanFactory.getBeanDefinitionNames()) {

		// ...

		Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
		
		// ...
		
		if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
			// ...
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	
	// ...

	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
		// ...
		Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
		if (configClass != enhancedClass) {
			if (logger.isTraceEnabled()) {
				logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
						"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
			}
			beanDef.setBeanClass(enhancedClass);
		}
	}
	// ...
}

enhance方法

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
	// ...
	Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
	// ...
	return enhancedClass;
}

newEnhancer方法

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(configSuperClass);
	enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

setCallbackFilter中定义方法增强

private static final Callback[] CALLBACKS = new Callback[] {
		new BeanMethodInterceptor(),
		new BeanFactoryAwareMethodInterceptor(),
		NoOp.INSTANCE
};

@Bean相关的处理是BeanMethodInterceptor
这就是cglib内容了,可以在方法中看到invokeSuper调用
关于增强了啥,暂时不做讨论了

private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

	@Override
	@Nullable
	public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
				MethodProxy cglibMethodProxy) throws Throwable {

	    // ...
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
		// ...
	}
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值