spring源码学习(一)——ioc初始化
spring源码学习(三)——初始化bean
spring源码学习(四)——aop
1.2.2 ConfigurationClassPostProcessor(BeanFactory后置处理器的执行)
在获取到BeanFactory后,就会执行invokeBeanFactoryPostProcessors(beanFactory)方法,执行BeanFactoryPostProcessor相应的方法。BeanFactoryPostProcessor中有一个非常重要的实现就是ConfigurationClassPostProcessor。它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import、@Bean等注解。在执行过程中,会先执行postProcessBeanDefinitionRegistry(),然后执行postProcessBeanFactory().
在看代码之前,先思考下我的两个疑问在@Configuration配置类里,1.@Bean方法的形参为什么自动会去容器中找到对应的bean注入,2.在@Bean方法中调用其他@Bean方法为什么返回的也是容器中的单例对象?这是我很好奇的,那接下来就看看在代码中,能不能解决我的疑惑吧。首先,我们来看看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);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// checkConfigurationClassCandidate()会判断一个是否是一个配置类,并为BeanDefinition设置属性为lite或者full。
// 在这儿为BeanDefinition设置lite和full属性值是为了后面在使用
// 如果加了@Configuration,那么对应的BeanDefinition为full;
// 如果加了@Bean,@Component,@ComponentScan,@Import,@ImportResource这些注解,则为lite。
//lite和full均表示这个BeanDefinition对应的类是一个配置类
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//解析@configuration注解的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
// 注意:这一步只会将加了@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap中
// 通过其他注解(例如@Import、@Bean)的方式,在parse()方法这一步并不会将其解析为BeanDefinition放入到BeanDefinitionMap中,而是先解析成ConfigurationClass类
// 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 将上一步parser解析出的ConfigurationClass类加载成BeanDefinition
// 实际上经过上一步的parse()后,解析出来的bean已经放入到BeanDefinition中了,但是由于这些bean可能会引入新的bean,
// 例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean,或者bean中存在被@Bean注解的方法
// 因此需要执行一次loadBeanDefinition(),这样就会执行ImportBeanDefinitionRegistrar或者ImportSelector接口的方法或者@Bean方法
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
//将ImportRegistry注册为Bean,以支持ImportAware @Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
因为这个方法太长,所以就留了一些比较重要的代码。可以看到核心是parser.parse(candidates)和this.reader.loadBeanDefinitions(configClasses)这两个方法。parser.parse(candidates)方法最终会调用ConfigurationClassParser#doProcessConfigurationClass方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//处理Component
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
//处理PropertySource
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
}
//处理任何@ComponentScan
//先找出类上的@ComponentScan和@ComponentScans注解的所有属性(例如basePackages等属性值)
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 解析@ComponentScan和@ComponentScans配置的扫描的包所包含的类
// (BeanDefinition可以理解为等价于BeanDefinitionHolder)
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//通过上一步扫描包下的类,有可能扫描出来的bean中可能也添加了ComponentScan或者ComponentScans注解.
//所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有ComponentScan和ComponentScans
// (这时这一步解析出componentScans为空列表,不会进入到if语句,递归终止)
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 同样,这里会调用ConfigurationClassUtils.checkConfigurationClassCandidate()方法来判断类是否是一个配置类
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//处理@Import 这一步只会将import注册的bean变为ConfigurationClass
processImports(configClass, sourceClass, getImports(sourceClass), true);
//处理@ImportResource注解引入的配置文件
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//处理@bean
//获取类中所有@bean的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
}
这里只有@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap,其他的则会解析成ConfigurationClass对象。然后再调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法将ConfigurationClass类加载成BeanDefinition。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//是否需要跳过
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 如果一个bean是通过@Import(ImportSelector)的方式添加到容器中的,那么此时configClass.isImported()返回的是true
// 而且configClass的importedBy属性里面存储的是ConfigurationClass就是将bean导入的类
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//处理@bean的方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如果bean上存在@Import注解,且import的是一个实现了ImportBeanDefinitionRegistrar接口,则执行ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
我们重点关注下@Bean的处理方法,看看能不能解决我的两个疑惑。可以看到这里遍历所有的@Bean的方法,调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod方法
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// 获取配置类以及注解方法的相关信息
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// 判断是否需要跳过这个类
...
// 提取@Bean注解的属性
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// 获取@Bean注册的别名
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// 注册所有的别名
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// 是否允许覆盖已存在的定义(判断依据来自isOverriddenByExistingDefinition方法,这里不做展开)
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
...
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//是否是静态方法
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
} else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
} else {
//设置FactoryBeanName,FactoryMethodName
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
//设置AutowireMode属性,之后@bean创建实例,形参会去getBean,容器中获取
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
//设置各种参数如:autowireCandidate initMethod destroyMethod
...
// Scope的代理信息获取
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
BeanDefinition beanDefToRegister = beanDef;
// 如果存在Scope代理,则使用代理类定义覆盖原有的类定义
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
这里主要关注BeanDefinition的AutowireMode属性被设置成AUTOWIRE_CONSTRUCTOR,并设置了FactoryBeanName,FactoryMethodName。这关系到后面创建bean实例的时候,解决形参注入的问题。现在先不继续讨论,到这里postProcessBeanDefinitionRegistry已经结束了。接来下看看postProcessBeanFactory方法,这个方法主要做了两件事:
// 对加了@Configuration注解的配置类进行Cglib代理
enhanceConfigurationClasses(beanFactory);
// 添加一个BeanPostProcessor后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
先来看看enhanceConfigurationClasses方法
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);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
//设置代理
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()));
}
//改变beanDefiniton的beanClass
beanDef.setBeanClass(enhancedClass);
}
}
先将类设置代理,然后将返回的代理类的class属性设置到BeanDefinition中,完成代理。ConfigurationClassEnhancer#enhance中完成了cglib动态代理的创建
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
//如果已经被代理过直接返回
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
return configClass;
}
//否则创建代理,核心代码为 newEnhancer()
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
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);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
这里设置的回调过滤CALLBACK_FILTER对应三种:
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
NoOp.INSTANCE就是什么都不做,BeanFactoryAwareMethodInterceptor为代理对象的beanFactory属性进行增强,负责拦截 BeanFactoryAware#setBeanFactory方法的调用,用于获取BeanFactory对象,因为增强的配置类实现了EnhancedConfiguration接口(也就是实现了BeanFactoryAwar接口)。BeanMethodInterceptor对加了@Bean注解的方法进行增强。我的第二个疑惑在这里就找到了答案。在BeanMethodInterceptor中,如果不是Object并且有@Bean注解,则执行intercept
public boolean isMatch(Method candidateMethod) {
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
//拿到beanName
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
//判断当前线程调用的方法名称和动态代理调用的方法名称是否一致,比较名称和参数,一致的说明是初次实例化调用,invoke父类方法
//不一致说明不是初次实例化调用(在其他方法中调用),此时不在进行实例化,而是直接从BeanFactory中获取
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
//调用方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//不一致调用getBean
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
执行@configuration类中的方法时,执行第一个@bean方法,会先走intercept方法,因为是初次实例化,则直接进行@Bean方法中的逻辑,在方法中,如果调用了其他的@Bean方法,则会比较两个bean方法名称与参数,如果不一致,就会去容器中获取。