Spring源码阅读之@Configuration注解、cglib代理

1,036 阅读6分钟

首先有以下代码

一个空的IndexDao类

public class IndexDao {
}
public class IndexDao1 {
	public IndexDao1(){
		System.out.println("IndexDao1构造");
	}
}
@ComponentScan("com.study")
public class AppConfig {

	@Bean
	public IndexDao1 indexDao1(){
		return new IndexDao1();
	}

	@Bean
	public IndexDao indexDao(){
		indexDao1();
		return new IndexDao();
	}
}
public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.register(AppConfig.class);
		context.refresh();
	}

输出如下:

IndexDao1构造
IndexDao1构造

现在给AppConfig类加上@Configuration注解再执行测试类:

IndexDao1构造

输出了一遍IndexDao1构造。 为什么加了@Configuration注解后就只输出可一遍呢?这个我们还要从spring的源码说起。

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors)
PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry)

通过阅读源码可以看到,spring在准备容器环境的时候会执行到上面这个方法;

跟进代码,会执行到下面,这个方法

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)

这个方法中有如下代码片段:

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				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));
			}
		}

这个代码片段中首先判断每一个BeanDefinition是全配置注解或者非全配置注解

ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef))

判断的依据其实就是看BeanDefinition有没有对应的属性

	public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
		return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
	}
public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
		return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
	}

第一次执行这里是还没有这两个属性的,所以会执行else if代码片段

			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}

进入checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)这个方法,有这样的代码片段:

		if (isFullConfigurationCandidate(metadata)) {
			// 如果存在@Configuration注解,则为BeanDefinition设置configurationClass属性为full
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}

这块代码判断,如果是一个全配置的类,就设置对应的属性。在这里判断是否是全配置的类很直接,就看这个类有没有@Configuration注解注解。

	public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
		return metadata.isAnnotated(Configuration.class.getName());
	}

如果是全配置类,那加上对应的属性。后面再判断这个类是否是全配置类就看有没有相应的属性了。

然后我们回到下面的方法

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors)

这个方法会执行到这个方法

invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

这个方法里面会执行BeanFactoryPostProcessor的postProcessBeanFactory方法。

跟进代码,会执行到下面的方法:

ConfigurationClassPostProcessor#enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory)
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			// 判断一个类是否是一个全注解类
			// 扫描是全注解类?full和lite的关系
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
				if (!(beanDef instanceof AbstractBeanDefinition)) {
					throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
							beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
				}
				else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
					logger.warn("Cannot enhance @Configuration bean definition '" + beanName +
							"' since its singleton instance has been created too early. The typical cause " +
							"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
							"return type: Consider declaring such methods as 'static'.");
				}
				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
			}
		}
		if (configBeanDefs.isEmpty()) {
			// nothing to enhance -> return immediately
			return;
		}

		ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
		for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
			AbstractBeanDefinition beanDef = entry.getValue();
			// If a @Configuration class gets proxied, always proxy the target class
			beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			try {
				// Set enhanced subclass of the user-specified bean class
				Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
				if (configClass != null) {
					// 完成对全注解类的cglib代理
					Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
					if (configClass != enhancedClass) {
						if (logger.isDebugEnabled()) {
							logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +
									"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
						}
						beanDef.setBeanClass(enhancedClass);
					}
				}
			}
			catch (Throwable ex) {
				throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
			}
		}
	}

ConfigurationClassUtils.isFullConfigurationClass(beanDef),判断一个注解是否是全配置类,前面已经经过一次判断了,如果是全配置类就会添加相应的属性。所以这里判断的时候直接看有没有相应的属性就行。当是一个全配置类的时候,就会先添加到configBeanDefs这个Map中。如果Map不为空,就一次为每个BeanDefinition完成cglib代理。结合我们开始直接写的代码,当我们给AppConfig这个类添加了@Configuration注解的时候,就会在这里生成AppConfig的代理类。

然后看看Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);这行代码里面是如何完成代理的。

	public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
		// 判断是否被代理过
		if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
			if (logger.isDebugEnabled()) {
				logger.debug(String.format("Ignoring request to enhance %s as it has " +
						"already been enhanced. This usually indicates that more than one " +
						"ConfigurationClassPostProcessor has been registered (e.g. via " +
						"<context:annotation-config>). This is harmless, but you may " +
						"want check your configuration and remove one CCPP if possible",
						configClass.getName()));
			}
			return configClass;
		}
		// 如果没有被代理就cglib代理
		Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
		if (logger.isDebugEnabled()) {
			logger.debug(String.format("Successfully enhanced %s; enhanced class name is: %s",
					configClass.getName(), enhancedClass.getName()));
		}
		return enhancedClass;
	}

这里判断是否被代理过其实就看有没有实现EnhancedConfiguration这个接口。如果有就直接返回代理,否则创建代理。

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
		Enhancer enhancer = new Enhancer();
		// 增强父类,cglib是基于继承来的
		enhancer.setSuperclass(configSuperClass);
		// 增强接口,为什么要增强接口
		// 便于判断,表示一个类已经被增强了
		enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
		enhancer.setUseFactory(false);
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		/**
		 * BeanFactoryAwareGeneratorStrategy是一个生成策略
		 * 主要是为生成的cglib类中添加成员变量$$beanFactory
		 * 同时基于接口EnhancedConfiguration的父接口BeanFactoryAware中的setBeanFactory方法,
		 * 设置此变量的值为当前context中的beanFactory,这样一来我们这个cglib代对象就有了beanFactory
		 * 有了beanFactory就能获得对象,而不用去通过方法获得对象了,因为通过放法获得对象不能控制过程
		 * 该beanFactory的作用是在this调用的拦截该调用,并直接在beanFactory中获得目标bean
		 */
		enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
		// 设置过滤方法,不能每次都去new
		enhancer.setCallbackFilter(CALLBACK_FILTER);
		enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
		return enhancer;
	}

cglib的代理是基于继承来的,这里设置了父类,也就是Appconfig,然后设置接口EnhancedConfiguration,这也就是刚为什么是可以通过判断是否由这个接口来断定是否被代理过了。

然后看new BeanFactoryAwareGeneratorStrategy(classLoader)这个类里面有这样的代码片段:

@Override
		protected ClassGenerator transform(ClassGenerator cg) throws Exception {
			ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
				@Override
				public void end_class() {
					declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
					super.end_class();
				}
			};
			return new TransformingClassGenerator(cg, transformer);
		}

declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);这里呢,就是申明了一个?beanFactory属性,可以理解为给Appconfig的代理类添加了这个属性,然后可以通过beanFactory获得代理对象。

CALLBACK_FILTER是一个过滤方法,里面会生成一个BeanMethodInterceptor(),里面有下面两处代码片段,这两处代码在实例化一个类之前的时候就会执行到:

ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

执行到这里的enhancedConfigInstance就是Appconfig的代理类了,在代理类的生成策略不是申明了?beanFactory属性么,在这里,就可以通过申明的?beanFactory属性得到beanFactory。

if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
	// The factory is calling the bean method in order to instantiate and register the bean
	// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
	// create the bean instance.
	if (logger.isWarnEnabled() &&
		BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
	logger.warn(String.format("@Bean method %s.%s is non-static and returns an object " +
						"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
						"result in a failure to process annotations such as @Autowired, " +
						"@Resource and @PostConstruct within the method's declaring " +
						"@Configuration class. Add the 'static' modifier to this method to avoid " +
						"these container lifecycle issues; see @Bean javadoc for complete details.",
			beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
	}
	return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}

return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);

从这里看出看来,结合我们之前的代码:

	@Bean
	public IndexDao1 indexDao1(){
		return new IndexDao1();
	}

	@Bean
	public IndexDao indexDao(){
		indexDao1();
		return new IndexDao();
	}

通过indexDao1()实例化IndexDao1、indexDao()实例化IndexDao的时候其实是通过

cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs)

来完成的。在执行indexDao()中的indexDao1();会执行

resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);

这里执行的时候会直接从上面得到的beanFactory中获得IndexDao1实例,解决bean的引用问题,而不是再通过代理方法来完成。其实就是不再“new”出一个实例了,而是直接从现有的beanFactory中直接拿出来,所以indexDao1()的构造方法就不会再执行到,“IndexDao1构造”也就只打印了一次。