1、ConfigurationClassPostProcessor如何应用
ConfigurationClassPostProcessor在Spring启动时为我们自动注册的
- 当我们使用了XmlWebApplicationContext并在配置文件中配置了
<context:annotation-config/>
或<context:component-scan/>
元素,XmlWebApplicationContext的loadBeanDefinitions()方法会使用XmlBeanDefinitionReader.loadBeanDefinitions(Resource) 方法在内部注册一个ConfigurationClassPostProcessor的BeanDefinition。 - 当使用AnnotationConfigWebApplicationContext时在loadBeanDefinitions方法被调用时会使用ClassPathBeanDefinitionScanner.scan()方法注册一个ConfigurationClassPostProcessor的BeanDefinition。
- 当使用的是AnnotationConfigApplicationContext会在scan(String...)方法被调用时注册ConfigurationClassPostProcessor的BeanDefinition。
以上三种注册ConfigurationClassPostProcessor的方式都是使用了AnnotationConfigUtils的静态方法registerAnnotationConfigProcessors()。
2、postProcessBeanDefinitionRegistry()原理分析
ConfigurationClassPostProcessor是BeanDefinitionRegistryPostProcessor的实现类,用来解析被@Configuration,@Component,@ComponentScan,@Import,@ImportResource标记的类,在postProcessBeanDefinitionRegistry()方法执行阶段会将进一步从被@Configuration标记的类上面寻找BeanDefintion注册到容器中。
@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);
}
//保存处理过的registry,避免重复处理
this.registriesPostProcessed.add(registryId);
//处理java bean配置形式的bean定义
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//取出容器中已经存在的所有bean 定义
String[] candidateNames = registry.getBeanDefinitionNames();
//判断每个bean定义是否是ConfigurationClass(被@Configuration,@Component,@ComponentScan,@Import,@ImportResource标记的),
//如果是则会给这个bean definition增加一个属性,避免重复解析
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// isFullConfigurationClass判断是否有full属性,isLiteConfigurationClass判断是否有lite属性
// 首次判断都为false,下面分支checkConfigurationClassCandidate方法会赋值这个属性
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//如果符合一个配置类型的java类定义,带有@Configuration为full
//带有@Component、@ComponentScan、@Import、@ImportResource之一或方法上有@Bean为lite
//加入configCandidates集合,后面根据优先级实例化配置bean
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
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
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;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
//如果AnnotationConfigWebApplicationContext设置了beanNameGenerator,则使用该beanNameGenerator
//否则组件扫描bean name是简单类名首字母小写,被导入的bean name是类的全限定名
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(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
//用于将被注解的类转换成ConfigurationClass供ConfigurationClassBeanDefinitionReader注册
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());
//解析一个ConfigurationClass后可能产生新的ConfigurationClass definition需要循环处理
do {
//解析ConfigurationClass的过程
parser.parse(candidates);
//@Configuration类不允许是final的,因为需要使用CGLIB生成代理对象,见postProcessBeanFactory方法。
//@Bean方法必须是可被重写的(可以是私有方法)静态方法不做处理
parser.validate();
//所有的配置类@Configuration
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());
}
//将@Configuration @Import @ImportResource @ImportRegistrar注册为bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
//如果有新的bean注册,判断是否符合配置类 进而继续解析
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
//ImportStack记录了哪些配置类通过@Import(看ImportSelector,ImportBeanDefinitionRegistrar接口)导入了哪些类
//后面通过ImportAwareBeanPostProcessor的功能实现了ImportAware接口的配置类可以得到导入类的注解属性
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
配置类ConfigurationClass代表了一个用户定义的@Configuration注解的类,其中包含了其自身和祖先标有@Bean的方法。
final class ConfigurationClass {
//带有该配置类注解信息的ClassMetadata,可获取类和类上面注解的信息
private final AnnotationMetadata metadata;
//类的来源
private final Resource resource;
//该类的bean name
@Nullable
private String beanName;
//是被哪个配置类@Import的
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
//自身和祖先的@Bean方法
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
//保存@ImportResource location与reader属性,后会使用reader解析location代表的资源转换一波配置类
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<>();
//@Import value属性是ImportBeanDefinitionRegistrar
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<>();
//记录不满足@Conditional value属性指定接口的@Bean方法,因为子类重写方法可能不满足条件,固需要记录,解析到父类就可直接跳过
final Set<String> skippedBeanMethods = new HashSet<>();
}
2.1、parse()方法解析
在看ConfigurationClassParser.parse()方法前先看看他的成员变量。
class ConfigurationClassParser {
private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();
private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
(o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector());
private final Log logger = LogFactory.getLog(getClass());
//构造器传入CachingMetadataReaderFactory
private final MetadataReaderFactory metadataReaderFactory;
//构造器传入FailFastProblemReporter
private final ProblemReporter problemReporter;
//容器传入
private final Environment environment;
//构造器传入DefaultResourceLoader
private final ResourceLoader resourceLoader;
//当前容器
private final BeanDefinitionRegistry registry;
//解析@ComponentScan
private final ComponentScanAnnotationParser componentScanParser;
//根据@Conditional注解指定的Condition接口来决定是否跳过此方法的解析
private final ConditionEvaluator conditionEvaluator;
//保存解析过的@Configuration类
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
//保存被解析类父类,避免多个子类导致同一个父类被解析多次
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<>();
//保存@PropertySource指定的资源
private final List<String> propertySourceNames = new ArrayList<>();
//保存@Import导入的类 key是正在解析的 value是被导入的
private final ImportStack importStack = new ImportStack();
//保存当@Import指定的是DeferredImportSelector,这类延迟解析 见parse方法
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
}
ConfigurationClassParser.parse()方法解析配置类,parse()方法内部会统一调用processConfigurationClass()方法。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//首次调用parse()方法处理的是AnnotatedBeanDefinition,通过@ImportResource加载的xml资源会走下面两个分支
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
this.deferredImportSelectorHandler.process();
}
protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
首先解析已存在的bean definition上的ConfigurationClass然后处理@Import指定的是DeferredImportSelector所返回的类。三个protected的parse()方法都是调用processConfigurationClass()方法,参数是ConfigurationClass对象。processConfigurationClass是真正处理@Configuration,此时还是不是将配置类注册为bean,而是通过此配置类继续找到其他的配置类,其他的配置类就属于被导入的配置类。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//根据@Conditional指定的Condition实现类match方法返回值决定是否跳过,具体看下面
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
//如果本次解析的configClass早已解析过了(class name一样就属于一个configClass),
//并且都是被导入的,则合并导入configClass的ConfigurationClass
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
//如果用户手动定义了一个ConfigurationClass,则去掉可能之前被自动@Import的类
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
// 递归处理配置类及其超类层次结构。
SourceClass sourceClass = asSourceClass(configClass);
do {
//从配置类解析一切可能的bean形式,内部类,成员方法,@Import等,返回值为父类,
//继续解析父类直到为null
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
//phase代表当前metadata属于哪个阶段,只有phase符合ConfigurationCondition,才会调用matches()方法
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
processConfigurationClass()方法中将ConfigurationClass简单包装成一个SourceClass对象为了将被注解的类以统一的方式处理,而不用关心类是如何加载的,因为类中会保存AnnotationMetadata对象,这个对象会包含类以及类上注解的所有信息。AnnotationMetadata是一个接口实现类有AnnotationMetadataReadingVisitor和StandardAnnotationMetadata,前者的获取需要SimpleMetadataReader,后者需要一个Class对象,所以SourceClass的构造器需要传入一个MetadataReader或Class。
private class SourceClass implements Ordered {
private final Object source; // Class or MetadataReader
private final AnnotationMetadata metadata;
public SourceClass(Object source) {
this.source = source;
if (source instanceof Class) {
this.metadata = new StandardAnnotationMetadata((Class<?>) source, true);
}
else {
this.metadata = ((MetadataReader) source).getAnnotationMetadata();
}
}
}
doProcessConfigurationClass()方法会构建一个完整的ConfigurationClass对象,换句话说就是填充上面提过的ConfigurationClass的那些成员属性通过读取配置类的注解、成员类和方法。
@Nullable
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);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
//将@PropertySource指定的properties资源合并到environment中,注意如果有多个@PropertySource命名相同name属性,
//则会合并相同名字的资源文件.并且填充configClass的propertySourceNames属性
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
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
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();
}
//有符合配置类的bean继续调用parse方法解析配置类重复doProcessConfigurationClass()的调用
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
// 一种静态批量注册bean的方式,不同于@Import可以指定三种形式,如@ImportResource("classpath:spring-dao.xml")
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);
}
}
// Process individual @Bean methods
// 遵照方法的先后声明顺序
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
// 支持接口默认方法的@Bean与普通类的@Bean没有区别
processInterfaces(configClass, sourceClass);
// Process superclass, if any
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;
}
doProcessConfigurationClass()方法用来解析配置类中的bean定义达到填充ConfigurationClass对象同时也会延展处理配置类,包括从以下几个方面来发现更多的配置类及bean:
1、 成员内部类;
2、 @ComponentScan注解指定包下扫描;
3、 @Import注解指定导入的类;
4、 @ImportResource指定的xml配置文件;
5、 @Bean标记的成员方法;
6、 @Bean标记接口默认方法;
2.1.1、内部类解析
找出成员内部类符合配置类的,调用processConfigurationClass()方法继续解析被发现的配置类。
//注册配置类里的成员类
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
//@Configuration @Component @ComponentScan @Import @ImportResource @Bean
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
//@Order注解排序
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
//避免循环导入
if (this.importStack.contains(configClass)) {
//同一个类被多次导入抛BeanDefinitionParsingException
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
//可以看到对一个配置类的解析是先深度后广度
processConfigurationClass(candidate.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
2.1.2、合并@PropertySource指定的属性到Environment
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
for (String location : locations) {
try {
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
Resource resource = this.resourceLoader.getResource(resolvedLocation);
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
// Placeholders not resolvable or resource not found when trying to open it
if (ignoreResourceNotFound) {
if (logger.isInfoEnabled()) {
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
private void addPropertySource(PropertySource<?> propertySource) {
String name = propertySource.getName();
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
if (this.propertySourceNames.contains(name)) {
// We've already added a version, we need to extend it
PropertySource<?> existing = propertySources.get(name);
if (existing != null) {
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
((ResourcePropertySource) propertySource).withResourceName() : propertySource);
if (existing instanceof CompositePropertySource) {
((CompositePropertySource) existing).addFirstPropertySource(newSource);
}
else {
if (existing instanceof ResourcePropertySource) {
existing = ((ResourcePropertySource) existing).withResourceName();
}
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(newSource);
composite.addPropertySource(existing);
propertySources.replace(name, composite);
}
return;
}
}
if (this.propertySourceNames.isEmpty()) {
propertySources.addLast(propertySource);
}
else {
String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
propertySources.addBefore(firstProcessed, propertySource);
}
this.propertySourceNames.add(name);
}
2.1.3、解析@ComponentScan,扫描它指定的类或某些包范围下的类
将配置类中@ComponentScan注解指定的所有属性传递给ComponentScanAnnotationParser的parse方法,parse()方法的返回值为@ComponentScan扫描包下符合bean定义(默认为@Component)的BeanDefination,再次判断这些BeanDefination中是否有符合ConfigurationClassUtils.checkConfigurationClassCandidate()的,如果有再次调用parse()方法做深层次的解析。
关于这个方法的核心类ClassPathBeanDefinitionScanner请参考《Spring源码分析-ClassPathBeanDefinitionScanner》中有详细介绍。
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//根据@ComponentScan的属性组装一个ClassPathBeanDefinitionScanner,由他负责扫描注册
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
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"));
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
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) {
//支持指定多个包 分隔符",; \t\n"
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
//支持指定Class所在的包
basePackages.add(ClassUtils.getPackageName(clazz));
}
//如果没有指明扫描范围,则使用当前处理的SourceClass所在的包
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//因为当前的declaringClass早已解析完了,需要排除掉
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
扫描重点是由ClassPathBeanDefinitionScanner完成的,这个类在之前的博文里已经详细介绍过,请看这篇《【Spring源码分析】-ClassPathBeanDefinitionScanner》 这里就不在啰嗦,到此为止知道他可以将@ComponentScan指定的包下面的类注册到容器就可以。
2.1.4、解析@Import注解
spring会找出配置类被标记@Import的所有注解,包括注解也被标记@Import的。
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
* *Set<SourceClass> imports = new LinkedHashSet<>();
* *Set<SourceClass> visited = new LinkedHashSet<>();
* *collectImports(sourceClass, imports, visited);
* *return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
* * * throws IOException {
*
* *if (visited.add(sourceClass)) {
* * * for (SourceClass annotation : sourceClass.getAnnotations()) {
* * * * *String annName = annotation.getMetadata().getClassName();
* * * * *// 如果是非@Import的注解,也会继续向上查找此注解上的@Import
* * * * *if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
* * * * * * collectImports(annotation, imports, visited);
* * * * *}
* * * }
* * * // @Impor的value属性当做新的sourceClass,传递给下面的processImports方法
* * * imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
* *}
}
处理@Import导入的类。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
//@Import的value属性指定的class集合
if (importCandidates.isEmpty()) {
return;
}
//检查不能循环导入
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
//如果是DeferredImportSelector,先不着急调用selectImports()方法,保存进deferredImportSelectorHandler中,在ConfigurationClassParser.parse()方法最后一步执行
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);
}
else {
//如果是普通ImportSelector实现类,则立即调用selectImports()方法,返回值作为如果又是ImportSelector或ImportBeanDefinitionRegistrar
//则继续递归调用processImports(),知道返回值为非ImportSelector,走else分支
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//如果是ImportBeanDefinitionRegistrar,先填充ConfigurationClass的importBeanDefinitionRegistrars属性,
//在ConfigurationClassPostProcessor的processConfigBeanDefinitions()方法中ConfigurationClassParser的parse()方法结束后使用ConfigurationClassBeanDefinitionReader
//的loadBeanDefinitions()方法中处理
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, 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(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支持Class类型:
- ImportSelector:如果是普通ImportSelector实现类,则立即调用selectImports()方法,返回值作为如果又是ImportSelector或ImportBeanDefinitionRegistrar。
- ImportBeanDefinitionRegistrar:如果是DeferredImportSelector,先不着急调用selectImports()方法,保存进deferredImportSelectorHandler中,在ConfigurationClassParser.parse()方法最后一步执行
- 普通类:当做ConfigurationClass继续调用ConfigurationClassParser.doProcessConfigurationClass()方法处理它。
2.1.5、解析@ImportResource注解
将locations指定的资源对象和reader指定的 BeanDefinitionReader保存到configClass中,后面会解析这些资源对象为bean。
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);
}
}
这段代码就是将@ImportResource属性locations指定的资源路径先保存在ConfigurationClass的importedResources属性中,然后也是同ImportBeanDefinitionRegistrar的处理时机在ConfigurationClassParser.parse()方法最后一步执行。这个资源解析交由reader属性指定的BeanDefinitionReader,默认使用XmlBeanDefinitionReader解析xml文件。
2.1.6、解析被@Bean标注的成员方法
将配置类标记@Bean注解的方法解析为MethodMetadata对象,随后将这些包装为BeanMethod保存到configClass中,然后统一注册为bean。
//检索当前SourceClass里所有@Bean方法
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
//超过一个被@Bean的方法才需要排序,先后声明顺序
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
上面代码的一段英文注释说,如果SourceClass的AnnotationMetadata是StandardAnnotationMetadata那就是使用了反射,反射获取类声明的方法顺序是不确定的,所以再尝试使用ASM框架它可以按方法声明的顺序得到方法声明,然后包装成MethodMetadata实例,StandardAnnotationMetadata包装的是StandardMethodMetadata,AnnotationMetadataReadingVisitor包装的是MethodMetadataReadingVisitor。MethodMetadata接口包含如下方法,可以方便获取方法的元数据。
public interface MethodMetadata extends AnnotatedTypeMetadata {
String getMethodName();
String getDeclaringClassName();
String getReturnTypeName();
boolean isAbstract();
boolean isStatic();
boolean isFinal();
boolean isOverridable();
}
将retrieveBeanMethodMetadata()方法返回的集合填充进ConfigurationClass的beanMethods的属性中,后等待ConfigurationClassParser.parse()方法使用ConfigurationClassBeanDefinitionReader处理。
2.1.7、解析当前SourceClass接口的@Bean方法
这一步与第6步一样都是为了获取@Bean方法的抽象定义放入ConfigurationClass的beanMethods属性中,只不过java8后支持接口带有默认方法,这一步就是发现这些默认方法有@Bean的。
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
processInterfaces(configClass, ifc);
}
}
2.1.8、如果当前SourceClass还有父类,将父类走一遍上述流程。
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();
}
}
到此为止经过ConfigurationClassParser.parse()方法已经将ConfigurationClass的属性都补全了(除了skippedBeanMethods),下面就是使用这些ConfigurationClass对象了。
2.2、validate()校验@Bean方法合法性
回到ConfigurationClassPostProcessor的processConfigBeanDefinitions()方法,得到ConfigurationClass对象后会使用validate()方法会做一个校验,配置类和@Bean方法不能是final的,因为需要使用CGLIB生成代理对象。
public void validate() {
* *for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
* * * configClass.validate(this.problemReporter);
* *}
}
public void validate(ProblemReporter problemReporter) {
* *// A configuration class may not be final (CGLIB limitation)
* *if (getMetadata().isAnnotated(Configuration.class.getName())) {
* * * if (getMetadata().isFinal()) {
* * * * *problemReporter.error(new FinalConfigurationProblem());
* * * }
* *}
*
* *for (BeanMethod beanMethod : this.beanMethods) {
* * * beanMethod.validate(problemReporter);
* *}
}
public void validate(ProblemReporter problemReporter) {
* *if (getMetadata().isStatic()) {
* * * // static @Bean methods have no constraints to validate -> return immediately
* * * return;
* *}
*
* *if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
* * * if (!getMetadata().isOverridable()) {
* * * * *// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
* * * * *problemReporter.error(new NonOverridableMethodError());
* * * }
* *}
}
2.3、processConfigBeanDefinitions()方法
校验ConfigurationClass对象合法性后会使用一个ConfigurationClassBeanDefinitionReader对象将这些ConfigurationClass解析为BeanDefiniton注册到容器中。下面看ConfigurationClassBeanDefinitionReader的唯一public方法loadBeanDefinitions()。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
//处理@Conditional核心方法前面已经分析过了
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;
}
//如果是被导入的类,则还没有注册为BeanDefiniton,则先将自身注册为BeanDefiniton,在注册属性代表的BeanDefinition
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
2.3.1、注册@Bean方法为BeanDefinition。
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
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;
}
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")));
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)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
//如果容器中已经定义了同名的BeanDefiniton
//同属于一个ConfigurationClass下直接抛异常
//否则使用已定义好的,抛弃这个@Bean方法定义的
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;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
//根据注解添加BeanDefinition属性@Lazy @Primary @DependsOn @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
//自动装配模式 @Bean默认Autowire.NO
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
//是否可以自动装配其他bean 默认true
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
//@Bean也可指定创建bean的初始化方法
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));
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
上面有一点需要注意:如果此@Bean的proxyMode属性不是ScopedProxyMode.DEFAULT和ScopedProxyMode.NO,则需要使用代理技术创建一个新的BeanDefinition取代这个同名的BeanDefinition,将原来的重新命名也注册到容器中。看下面具体代码:
final class ScopedProxyCreator {
private ScopedProxyCreator() {
}
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
public static String getTargetBeanName(String originalBeanName) {
return ScopedProxyUtils.getTargetBeanName(originalBeanName);
}
}
public abstract class ScopedProxyUtils {
private static final String TARGET_NAME_PREFIX = "scopedTarget.";
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
//原始bean重新命名scopedTarget.originalBeanName
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
//内部使用ProxyFactory创建代理对象,通过targetBeanName从容器获取目标对象
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
//代理类保存着原始类的bean name
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
//代理目标类
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
//代理目标接口
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
//避免使用容器里的原始类
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
public static String getTargetBeanName(String originalBeanName) {
return TARGET_NAME_PREFIX + originalBeanName;
}
public static boolean isScopedTarget(@Nullable String beanName) {
return (beanName != null && beanName.startsWith(TARGET_NAME_PREFIX));
}
}
2.3.2、注册@ImportResource指定资源代表的BeanDefinition
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
importedResources.forEach((resource, readerClass) -> {
// Default reader selection necessary?
if (BeanDefinitionReader.class == readerClass) {
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
// When clearly asking for Groovy, that's what they'll get...
readerClass = GroovyBeanDefinitionReader.class;
}
else {
// Primarily ".xml" files but for any other extension as well
readerClass = XmlBeanDefinitionReader.class;
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// Instantiate the specified BeanDefinitionReader
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
// Delegate the current ResourceLoader to it if possible
if (reader instanceof AbstractBeanDefinitionReader) {
AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
abdr.setResourceLoader(this.resourceLoader);
abdr.setEnvironment(this.environment);
}
readerInstanceCache.put(readerClass, reader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}
// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
reader.loadBeanDefinitions(resource);
});
}
默认处理xml资源,也可以自定义BeanDefinitionReader解析任意资源完成bean的注册。
2.3.3、如果@Import指定的是ImportBeanDefinitionRegistrar可以完成批量注册
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry));
}
参考org.springframework.context.annotation.AspectJAutoProxyRegistrar
3、postProcessBeanFactory()原理分析
到这为止对@Configuration类解析注册的过程就完成了,下面分析ConfigurationClassPostProcessor的postProcessBeanFactory()方法的,看看他他是如何增强@Configuration类的。
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);
}
//加强@Configuration类
enhanceConfigurationClasses(beanFactory);
//此BeanPostProcessor会将实现了ImportAware接口的类注入ConfigurationClassParser的ImportStack
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
核心方法enhanceConfigurationClasses用来将标记@Configuration的配置类的BeanDefinition的beanClass替换为经过CGLIB加强过的,这样在实例化此bean的时候,就可以使用替换的代理类来创建对象了。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
* *Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
* *for (String beanName : beanFactory.getBeanDefinitionNames()) {
* * * BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
* * * //只增强@Configuration类
* * * if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
* * * * *//Spring提供的所有BeanDefinition的实现类都继承了AbstractBeanDefinition
* * * * *if (!(beanDef instanceof AbstractBeanDefinition)) {
* * * * * * throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
* * * * * * * * * beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
* * * * *}
* * * * *//如果已经存在了一个实例,那么不会增强它,造成这个现象的原因是@Bean方法的返回类型BeanDefinitionRegistryPostProcessor
* * * * *else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
* * * * * * logger.info("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增强配置类,使其拥有调用@Bean方法总是返回一个对象的能力
* *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) {
* * * * * * 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);
* * * * * * }
* * * * *}
* * * }
* * * catch (Throwable ex) {
* * * * *throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
* * * }
* *}
}
ConfigurationClassEnhancer.enhance()方法会使用cglib返回配置类的一个代理类,这个代理类拦截了@Bean方法,重复调用这个方法总是返回同一个对象(默认行为,除非指定@Sope),使其拥有单例的能力。
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;
}
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();
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;
}
private Class<?> createClass(Enhancer enhancer) {
Class<?> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
enhancer指定了父类为EnhancedConfiguration,此类实现了BeanFactoryAware接口,所以就拥有了setBeanFactory()方法因此Spring容器会将持有的BeanFactory通过此方法传递给代理对象。enhancer又配置了一个BeanFactoryAwareGeneratorStrategy,它会给代理类添加一个名为"$$beanFactory"并且类型为BeanFactory的字段。加上拦截器BeanFactoryAwareMethodInterceptor结合这三者,BeanFactoryAwareMethodInterceptor起作用的时候就会将$$beanFactory赋值为当前容器,而后代理对象就拥有了Spring容器。
public interface EnhancedConfiguration extends BeanFactoryAware { }
private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy {
@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);
}
}
enhancer还设置了一组拦截器(CALLBACKS),每当执行代理类的一个方法都会经过拦截器,至于选择哪个拦截器是由拦截器的isMatch()方法决定的,CALLBACKS是三个Callback实例,分别起到不同的作用。
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
当Spring容器调用目标对象的setBeanFactory()方法时,BeanFactoryAwareMethodInterceptor会拦截到,以为它的isMatch()犯法。
public boolean isMatch(Method candidateMethod) {
return isSetBeanFactory(candidateMethod);
}
public static boolean isSetBeanFactory(Method candidateMethod) {
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
后执行拦截器的intercept()方法,此方法就是如上所说将BeanFactory保存到代理对象的$$beanFactory的属性,供代理对象使用,因为BeanMethodInterceptor生效的时候会用到。
如果调用目标对象的方法不是setBeanFactory()方法并且是@Bean方法则使用BeanMethodInterceptor加强(代理)此方法。值得注意的是当检查请求的bean是否是FactoryBean。如果是这样,创建一个子类代理来拦截对getObject()的调用并返回任何缓存的bean实例。作用域代理工厂bean是一种特殊情况,不应该进一步代理。
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
//获取被代理的目标bean的bean name scopedTarget.beanName
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.
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
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
//如果我们显示的设置了@Scope属性proxyMode为代理模式,则不需要进一步代理了
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//Spring通过通过工厂方法创建时会保存创建对象的工厂方法,所以说第一次调用创建对象方法不会被拦截
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()));
}
//直接使用Spring 工厂方法创建对象
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//如果不是第一次调用此方法,从容器中直接获取达到单利目的
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {
// The user (i.e. not the factory) is requesting this bean through a call to
// the bean method, direct or indirect. The bean may have already been marked
// as 'in creation' in certain autowiring scenarios; if so, temporarily set
// the in-creation status to false in order to avoid an exception.
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, false);
}
boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
if (useArgs && beanFactory.isSingleton(beanName)) {
// Stubbed null arguments just for reference purposes,
// expecting them to be autowired for regular singleton references?
// A safe assumption since @Bean singleton arguments cannot be optional...
for (Object arg : beanMethodArgs) {
if (arg == null) {
useArgs = false;
break;
}
}
}
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
// Detect package-protected NullBean instance through equals(null) check
if (beanInstance.equals(null)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] returned null bean; resolving to null value.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName()));
}
beanInstance = null;
}
else {
String msg = String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
try {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - simply no detailed message then.
}
throw new IllegalStateException(msg);
}
}
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}
@Override
public boolean isMatch(Method candidateMethod) {
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}