日积月累,水滴石穿 ?
前言
上篇讲到 refresh()
中invokeBeanFactoryPostProcessors
方法,该方法会执行所有
BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry()
方法以及BeanFactoryPostProcessor
的postProcessBeanFactory()
方法。其重中之中就是 postProcessBeanDefinitionRegistry
方法。
在无自定义的情况下,Spring
容器中就一个实现了 BeanDefinitionRegistryPostProcessor
的 BeanDefinition
,它的名字是 ConfigurationClassPostProcessor
。
作用
各位可能还不了解 ConfigurationClassPostProcessor
这个类的作用,小杰就先说说。
在 Spring
中 Bean
的都是基于 BeanDefinition
去创建的,所以需要先有 BeanDefinition
,才会有 Bean
。
一个 BeanDefinition
就代表着一个类,那一个类是怎么被解析为BeanDefinition
呢?这个就是由 ConfigurationClassPostProcessor
来完成的。
ConfigurationClassPostProcessor
是一个BeanFactory
后置处理器,会对写有 @Configuration
,@ComponentScan
,@ComponentScans
、@ImportResource
、@Import
、@Component
、@Bean
注解的类解析为 BeanDefinition
,并添加到容器。再由后续的流程将之注册为 Bean
。
ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
}
可以看到实现了BeanDefinitionRegistryPostProcessor
,而 BeanDefinitionRegistryPostProcessor
接口继承了 BeanFactoryPostProcessor
接口,那就会重写其postProcessBeanDefinitionRegistry
方法和postProcessBeanFactory
方法。
一、postProcessBeanDefinitionRegistry
我们先来看 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);
}
// registriesPostProcessed在本类的 postProcessBeanFactory 方法中会用到
// 记录 registryId
this.registriesPostProcessed.add(registryId);
// 寻找配置类对应的BeanDefinition然后进行处理
// 比如开始扫描
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions
核心逻辑在processConfigBeanDefinition()
方法中。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历BeanDefinitionRegistry中当前存在的beanDefinition,从中找出那些 beanDefinition 是配置 bean
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);
}
}
// 检查BeanDefinition是不是配置类候选者,那什么样的BeanDefinition符合呢?
// 1. 存在@Configuration的就是配置类
// 2. 存在@Component,@ComponentScan,@Import,@ImportResource
// 3. 存在@Bean标注的方法
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//构建一个 BeanDefinitionHolder,添加到 configCandidates 集合中
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
// 没有找到配置类
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// 将配置类进行排序,根据 @Order 注解进行排序,数字越低优先级越高
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
// 当前 BeanFactory 是不是支持单例bean的注册,如果支持则设置一个 BeanNameGenerator
// 用来在扫描 @Component 和 @Import 某个Bean时取名字
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
// localBeanNameGeneratorSet 默认为 false
if (!this.localBeanNameGeneratorSet) {
// 程序员可以指定一个beanName生成器 applicationContext.setBeanNameGenerator()
// 不指定则使用默认的 ConfigurationBeanNameGenerator
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
// 配置 bean 解析器,解析器里存在 registry,所以在解析的过程中可以往 registry 中添加 BeanDefinition
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 {
// 对配置BeanDefinition进行解析,解析完后会生成ConfigurationClass
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());
}
// 利用 reader 解析 ConfigurationClass,同时注册 BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
// 省略部分代码 ...
}
while (!candidates.isEmpty());
// 省略部分代码 ...
}
方法一:checkConfigurationClassCandidate
检查BeanDefinition
是不是配置类。配置类分两种 full、lite,如果加了@Configuration
,那么配置类类型为full
,如果加了@Bean
,@Component
,@ComponentScan
,@Import
,@ImportResource
这些注解,配置类类型为lite
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// 省略部分不重要的代码
// 获取 Configuration 注解的属性信息,配置类分两种
// 1、被 @Configuration 标记的配置类为 full,full 的配置类会生成代理对象
// 2、其他的配置类为 lite
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// proxyBeanMethods 默认值为 true
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
// CONFIGURATION_CLASS_FULL = full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 注意,并不是说没有 @Configuration 注解,当前 BeanDefinition 就不是一个配置类
// 还要注意 isConfigurationCandidate 方法,会检查是否存在
// @Component, @ComponentScan,@Import,@ImportResource,@Bean注解
// 只是配置类类型为 lite
else if (config != null || isConfigurationCandidate(metadata)) {
// CONFIGURATION_CLASS_LITE = lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
// 返回false,表示不是一个配置类
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
isConfigurationCandidate
检查是否存在@Component
, @ComponentScan
,@Import
,@ImportResource
,@Bean
注解,如果有,当前BeanDefinition
是一个配置类,类型为 lite
。
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
// 不考虑接口上的注解
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
// candidateIndicators 是一个静态的 Set 集合
// 集合中有四个值,分别为@Component,@ComponentScan,@Import,@ImportResource这四个注解
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
// 查找有没有加了@Bean注解的方法
try {
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
方法二:parse
该方法会对上面找到的配置类进行解析,也就是解析类上的注解。会将@ComponentScan
扫描到的类,@Import
导入的类,@Bean
方法所在的类解析成ConfigurationClass
类。
@Component
, @ComponentScan
,@Import
,@ImportResource
,@Bean
。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 遍历多个配置类的 BeanDefinition
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 根据BeanDefinition类型的不同,调用parse()不同的重载方法
// 但是内部都是调用 processConfigurationClass 方法
// 小杰这就分析 AnnotatedBeanDefinition 入口
// 处理有注解的 BeanDefinition
if (bd instanceof AnnotatedBeanDefinition) {
// 处理注解的信息
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 如果@Import 导入的类的类型为 DeferredImportSelector
// 这句话才会生效,内部其实也是调用 processImports 方法。
this.deferredImportSelectorHandler.process();
}
// 处理注解的信息
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
// 构建一个 ConfigurationClass 对象,表示配置类信息,包括注解信息
// 和 beanName,以及resource属性,表示配置类的类路径地址
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
processConfigurationClass
processConfigurationClass
方法中调用 doProcessConfigurationClass
方法,这才是核心处理逻辑方法。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 省略部分代码
// sourceClass 将类简单的包装了一下,可以忽略
SourceClass sourceClass = asSourceClass(configClass);
do {
//循环解析,核心逻辑
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
// 配置类可能存在父类,所以需要递归处理
while (sourceClass != null);
// 把当前配置类存在configurationClasses Map里面
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 1. 如果配置类上有@Component注解,则要获得类中的内部类,判断内部类上是否有 @Component、@ComponentScan、@Import、@ImportResource注解
// 如果有调用 processConfigurationClass
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
// 2. 解析@PropertySource注解,该注解的作用可以加载指定的配置文件
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
// 3. 解析@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) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 扫描指定包路径及子包下的类,得到 BeanDefinitionHolder,BeanDefinitionHolder 中包含 BeanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 检查扫描所得到 BeanDefinition 是不是配置 Bean
// 基本上都有 @Component 注解,所以都是配置类,继续需要进行解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
// 4. 解析@Import。
// getImports方法返回 sourceClass 上定义的 Import注解中所导入的类的信息的集合
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
// 5. 解析@ImportResource,得到导入进来的spring的xml配置文件,然后解析
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
//xml文件地址
String[] resources = importResource.getStringArray("locations");
//得到解析xml文件的解析器
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
// 添加到ConfigurationClass 类 importedResources Map 属性中,后续进行解析
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
// 6. 解析配置类中的加了@Bean注解的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
// 将找到的方法添加到 ConfigurationClass 类 beanMethods Set 属性中,后续进行解析
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
// 7. 如果配置类实现了某个接口,那么则解析该接口中的加了@Bean注解的默认方法
// 添加到 ConfigurationClass 类 beanMethods Set 属性中,后续进行解析
processInterfaces(configClass, sourceClass);
// Process superclass, if any
// 8. 如果有父类,则返回父类给上层遍历进行处理
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
方法逻辑挺长的,大体流程如下:
- 1、配置类上有
@Component
注解,则要获得配置类中的内部类,判断内部类上是否有@Component、@ComponentScan、@Import、@ImportResource
注解,如果有则代表内部类也是配置类,则需要调用processConfigurationClass
方法。相当于递归。 - 2、处理解析
@PropertySource
注解。 - 3、解析
@ComponentScan、ComponentScans
注解,扫描指定包路径及子包下的类。由于扫描所得到BeanDefinition
有可能也是配置类,所以也需要递归处理解析。 - 4、处理@Import注解。
- 5、处理@ImportResource注解,解析 xml 文件。
- 6、处理@Bean注解的方法
- 如果配置类实现了某个接口,那么则解析该接口中的加了@Bean注解的默认方法
- 8、如果有父类,则返回父类给上层遍历进行处理
简单的流程步骤这里就不再分析了。
流程一
核心逻辑在 this.componentScanParser.parse
方法中。
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// useDefaultFilters 值默认为 true,所以 includeFilters 中默认就注册了一个 @Component 注解对应的 Filter
// ClassPathBeanDefinitionScanner 这个对象在讲 Spring 启动流程中已经分析了
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// 设置BeanName生成器
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
// 得到 @ComponentScan 中 includeFilters 的值 ,并设置 IncludeFilter,
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
// 得到 @ComponentScan 中 excludeFilters 的值 ,并设置 ExcludeFilter
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
// 设置懒加载
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
// declaringClass 为传入的配置类全路径,例如:com.cxyxj.xx.AppApplication
// 默认的排除过滤
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
// 开始扫描包路径,得到 BeanDefinitionHolder
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
不出意外,还是包含一个 doScan
方法。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 扫描包路径得到BeanDefinition,得到的BeanDefinition是空的,还没有解析类上所定义的注解信息
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 得到Scope的信息,并设置
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 得到beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
// 生成BeanDefinitionHolder并注册到registry中
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 根据 @@Scope 属性 proxyMode 的值,确定是否需要产生代理对象
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
// Scope注解中的ProxyMode属性有四个取值
// 1.DEFAULT:默认值,默认情况下取no
// 2.NO:不开启代理
// 3.INTERFACES:使用jdk动态代理
// 4.TARGET_CLASS:使用cglib代理
// 假如有一个单例beanA,其中有一个属性B,B的Scope是session,此时,容器在启动时创建A的过程中需要注入B属性,
// 但是B的scope是session,这种情况下是注入不了的,是会报错的
// 但是如果将B的Scope的ProxyMode属性配置为INTERFACES/TARGET_CLASS时,那么B就会生成一个ScopedProxyFactoryBean类型的BeanDefinitionHolder
// 在A注入B时,就会注入一个ScopedProxyFactoryBean类型的Bean
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
// 是否使用cglib
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 创建ScopedProxyFactoryBean类型的BeanDefinitionHolder
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
findCandidateComponents
findCandidateComponents
的方法值为 Set<BeanDefinition>
,可以得知,扫描就是在这个方法干的。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
// Spring提供了一种支持更快速扫描的机制,就是编译时直接创建一个静态的,ASM技术
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
// 扫描@Component,扫描 basePackage 下的所有类,看是否有@Component注解
return scanCandidateComponents(basePackage);
}
}
对于 ASM 技术,有兴趣的伙伴可以去网上了解下。小杰不会。我们来看最笨的方法 scanCandidateComponents
。
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
// 扫描类,得到BeanDefinition
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//路径下所有的类
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
// MetadataReader 包含了对应 class 的元信息以及注解元信息。
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 判断一个类是不是Component
if (isCandidateComponent(metadataReader)) {
// 通过扫描@Component得到的BeanDefinition类型为ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
// 再进一步验证
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
//将 sbd 添加到 Set 集合中
candidates.add(sbd);
}
// 省略诸多 catch、else
return candidates;
}
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//如果读取的类的注解在排除注解过滤规则中,返回false
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//如果读取的类的注解在包含的注解的过滤规则中,则返回ture
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
//如果读取的类的注解既不在排除规则,也不在包含规则中,则返回false
return false;
}
// 判断一个类是不是Component
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 不匹配,扫描到的类在 excludeFilters 中,返回false,代表不是一个备选的Component
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 匹配,只有通过了 includeFilters 的验证才算是一个备选的Component
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
excludeFilters
、includeFilters
都是 @ComponentScan
注解的属性,如果不熟悉,可以前往:@ComponentScan 注解详解
流程四
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// 以下会判断 @Import(UserService.class) 导入的类型
for (SourceClass candidate : importCandidates) {
// 如果导入的类实现了 ImportSelector 接口
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
// 得到 ImportSelector 对象
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
// DeferredImportSelector 是 ImportSelector 的子接口
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 执行 selectImports 方法,得到 selectImports 方法的返回值(需要导入的类名)。
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//包装为 SourceClass
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 将导入的类作为配置类,进行递归解析。可能可能还带有 @Import 或者其他注解,
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 实现了 ImportBeanDefinitionRegistrar 接口
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
// 如果@Import注解中的类实现了ImportBeanDefinitionRegistrar接口
// 就把该类的实例放入 ConfigurationClass类中属性 importBeanDefinitionRegistrars Map中,
// 后面再执行该实例的 registerBeanDefinitions 方法
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 如果导入的类就是一个普通的类,将其作为配置类进行解析
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 调用 processConfigurationClass 方法
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
如果配置类上存在@Import
注解,那么需要判断导入类的类型:
- 如果是
ImportSelector
,那么调用执行selectImports
方法得到类名,然后在把这个类当做配置类进行解析**(递归)** - 如果是
ImportBeanDefinitionRegistrar
,那么则生成一个ImportBeanDefinitionRegistrar
实例对象,并添加到配置类对象中(ConfigurationClass
)的importBeanDefinitionRegistrars
属性中。 - 如果是普通类,做作为配置类进行处理。
流程 4(ImportBeanDefinitionRegistrar
类型)、流程 5、流程6都没有真正的将之解析为 BeanDefinition
,都是先存到 ConfigurationClass
类的属性中。
流程七
流程 7,只是Spring
多了一种注册 Bean 的写法。写法如下:
public interface UService {
@Bean
default UserService u(){
return new UserService();
}
}
@Service
public class UServiceImpl implements UService{
}
UServiceImpl
是一个配置类,且实现了 UService
接口,接口中有一个默认的实现方法 u,该方法上添加了@Bean
注解。经过第(7)步的解析,会添加到 ConfigurationClass
类 beanMethods
属性中,后续进行解析。
会向Spring
容器中注册一个UserService
类型的 Bean。
经过 processConfigurationClass
方法的解析后,我们会得到许多个配置类,这些配置类存放在 ConfigurationClassParser
类的configurationClasses
属性中。存储结构如下:
接下来就利用reader
来进一步解析ConfigurationClass
,因为还有一部分没有被生成 BeanDefinition
。
我们回到 processConfigBeanDefinitions
方法中,找到 this.reader.loadBeanDefinitions(configClasses);
代码。
方法三 loadBeanDefinitions
该方法就是将另外一部分生成BeanDefinition
,被@Import
、@Bean
、@ImportedResource
注解方式注册的类解析成BeanDefinition
,然后注册到BeanDefinitionMap
中。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
//循环调用
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 省略....
// 当前配置类是不是通过 @Import 注解导入进来的,如果是则解析该类上面的注解
// 比如 @Scope,@Lazy 这些注解信息,然后构建成 BeanDefinition
// 并注册到 BeanDefinitionMap 中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//getBeanMethods:@Bean注解标注的方法,解析并注册到 BeanDefinitionMap 中
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 从 @ImportedResource 导入进来的资源文件中加载BeanDefinition,并注册到 BeanDefinitionMap 中
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如果@Import注解中的类实现了ImportBeanDefinitionRegistrar接口
// 调用 ImportBeanDefinitionRegistrar 对象的 registerBeanDefinitions 方法加载 BeanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
除了loadBeanDefinitionsForBeanMethod
之外,其余方法就不再分析了,整体逻辑一目了然的。
@SuppressWarnings("deprecation") // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// @Bean标注方法的来源
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
// 方法名称
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// 获得 @Bean 的信息
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
// Consider name and any aliases
//获得所有别名
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
//如果指定了别名,则第一个别名作为 beanName,负责使用 方法名称作为 beanName
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
// 注册别名
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
// 判断 beanName 是否已经被加载过了
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
// 构建 BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
// 被@Bean标注的方法是静态,则使用静态工厂注入
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 {
// 实例工厂注入
// instance @Bean method
// factory-bean 配置实例化工厂类的名称
beanDef.setFactoryBeanName(configClass.getBeanName());
// 指定工厂方法
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
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());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Consider scoping
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;
}
}
// Replace the original bean definition with the target one, if necessary
// 使用需要创建代理对象
BeanDefinition beanDefToRegister = beanDef;
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);
}
if (logger.isTraceEnabled()) {
logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
// 注册BeanDefinition
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
看完上述逻辑,你会得到以下知识:
@Bean
可以指定别名,第一个别名会作为beanName
,如果没指定别名,会将方法名称作为别名。@Bean
是通过factory-method
实例化对象的。
具体使用请移步前往:XML文件的读取-factory-method的使用
上面几千字将 postProcessBeanDefinitionRegistry
方法分析完啦!接下来看 postProcessBeanFactory
方法。
二、postProcessBeanFactory
通过前面的学习我们应该知道 postProcessBeanFactory
是对BeanFactory
进行处理的。那这个方法是怎么处理的呢,方法干了两件事:
- 对被
@Configuration
标注的类,使用CGLIB代理生成代理对象。 - 向
beanPostProcessors
集合中添加一个ImportAwareBeanPostProcessor
Bean的后置处理器。
@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);
// 是否需要进行解析
// factoryId 在执行 postProcessBeanDefinitionRegistry 方法时,已经添加到了 registriesPostProcessed 集合中
// 所以该判断永远不会成立
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 对被 @Configuration 标注的类,使用CGLIB代理生成代理对象
enhanceConfigurationClasses(beanFactory);
// 向 beanPostProcessors 中添加一个 Bean的后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
enhanceConfigurationClasses
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// configClassAttr 的值有两种:full、lite
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
// 省略代码 。。。
// 被@Configuration标注的配置类就是 full
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
// 省略代码 。。。
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
// 加了@Configuration注解的配置类的BeanDefinition
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
// 没有什么可增强的 -> 立即返回
return;
}
// 生成被 @Configuration 标注类的代理对象
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()));
}
// 将增强类设置给 beanDefinition,后续基于 BeanDefinition 产生的bean就是增强类的对象了
beanDef.setBeanClass(enhancedClass);
}
}
}
- enhancer.enhance
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
// 省略一大串日志 。。。
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
return enhancedClass;
}
上面的核心方法为newEnhancer
,我们来看 newEnhancer
方法。
- newEnhancer
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
// 对代理对象设置父类
enhancer.setSuperclass(configSuperClass);
// 对代理对象设置父接口
// EnhancedConfiguration 继承了 BeanFactoryAware
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 添加了两个 MethodInterceptor ,BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
// CGLIB 的增强就是执行 MethodInterceptor类 的 intercept 方法
// BeanMethodInterceptor :对加了@Bean注解的方法进行增强
// BeanFactoryAwareMethodInterceptor:对实现了 BeanFactoryAware 接口,调用 setBeanFactory() 方法
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
这方法创建了一个 Enhancer
实例。并设置了代理对象的父类、代理对象的父接口 EnhancedConfiguration
,代理对象的增强逻辑 BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
。
addBeanPostProcessor
向 beanPostProcessors
中添加一个 Bean的后置处理器,类型为 ImportAwareBeanPostProcessor
,在后续 Bean 的生命周期中会触发。我们一起看看 ImportAwareBeanPostProcessor
的代码逻辑。
private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private final BeanFactory beanFactory;
public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessProperties method attempts to autowire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ImportAware) {
ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
if (importingClass != null) {
((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
}
ImportAwareBeanPostProcessor
中就重写了两个方法,postProcessProperties
方法与 postProcessBeforeInitialization
方法。
- postProcessProperties:如果当前 bean 实现了
EnhanceConfiguration
类,则为它设置beanFactory
属性赋值。如果忘记了EnhanceConfiguration
,看看enhanceConfigurationClasses
方法。 - postProcessBeforeInitialization:处理
ImportAware
回调。
为什么加了 @Configuration注解的类需要被代理呢?
不加 @Configuration注解
我们来看一个现象,准备如下代码,两个@Bean
标注的方法 u()
、u2
,在 u2
中调用 u
。会打印几次====== u
?1次还是2次呢?
@ComponentScan(basePackages = {"com.cxyxj.conf"})
public class AppApplication {
@Bean
UserService u(){
UserService userService = new UserService();
System.out.println("====== u == " + userService);
return userService;
}
@Bean
BeanTest u2(){
u();
System.out.println("====== u2");
return new BeanTest();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppApplication.class);
UserService bean = context.getBean(UserService.class);
System.out.println("bean = " + bean);
}
}
启动结果如下:
结果是打印了两次。返回的对象并不一致,这个两个对象的作用域都是singleton
, 这不就违背了Spring的单例原则吗?即一个bean在一个IoC容器中只有一个实例。
各位是否还记得 @Bean
是如何创建 Bean 实例的吗?采用的是 factory-method
方式进行实例化,而这种方式底层是通过 反射 。
源码位于 SimpleInstantiationStrategy
类 instantiate
方法。
前往博文:Supplier、工厂方法实例化Bean
- 通过反射执行
u()
方法,将返回的的对象放入单例池中。 - 通过反射执行
u2()
方法,再调用u()
,这没办法从单例池获得UserService
对象,只能重新创建UserService
对象,并且这次创建的对象没办法放入单例池中。调用完u()
,将创建的BeanTest
对象放入单例池。
加 @Configuration注解
在类上加上 @Configuration
注解,进行启动。结果如下:
可以看出加上@Configuration
注解之后,u()
只被调用了一次。Spring 是怎么保证的呢?
各位还记得小杰在enhanceConfigurationClasses
方法中提到,在由 CGLIB 产生代理对象的过程中,会构建一个 Enhancer
实例,会给Enhancer
实例的 filter
属性添加了两个 MethodInterceptor
,分别是 BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
。其中 BeanMethodInterceptor
就是处理被 @Bean
注解的方法。
BeanMethodInterceptor
实现了MethodInterceptor
接口,会重写其 intercept
,这也是 CGLIB 代理的核心方法,代码如下:
- enhancedConfigInstance:CGLIB 创建的代理对象
- beanMethod:代理类执行的方法,本例中的
u()
、u2()
- beanMethodArgs:需要传给方法的参数
- cglibMethodProxy:方法代理,不需要过于关心
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// 得到bean工厂
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// beanMethod对应的beanName
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
// 确定此 bean 是否是作用域代理
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
// 如果beanFactory中存在beanName并且也存在&+beanName所对应的bean,那么这个bean是一个FactoryBean
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
// FactoryBean对象
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
// 对FactoryBean对象进行增强,当userService()中调用userFactoryBean()时,返回的是UserFactoryBean的代理对象
// 因为不能返回getObject方法的bean,也不能直接方法上面的factoryBean对象,因为如果返回的是factoryBean对象
// 如果后面调用getObject方法就会产生问题,而产生一个代理对象就可以对getObject方法进行代理,保证getObject方法返回的是同一个bean
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
// 比如当前正在进行实例化的是u2()方法所对应的bean,而在u2()方法中会调用u()方法
// 这个时候下面这个判断等于false,而等于false,就不会真正去执行u()方法了,就会直接去beanFactory中去获取bean
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.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(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()));
}
// 真正执行 @Bean 注解标注的方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
// 直接去beanFactory中去获取bean
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
在执行 factoryMethod.invoke(factoryBean, args)
时,就会进入到上述逻辑中。 好了,这就是本文的全部内容。
- 我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。