前言
Spring从3.0开始支持JavaConfig配置,具体来说就是可以完全通过注解来开启Bean扫描,声明Bean,导入properties文件等。
主要有以下注解:
@Configuration: 标识此Bean是一个配置类,接下来开始解析此类
@ComponentScan: 开启注解扫描,默认扫描@Component注解
@Import: 导入其他配置类
@ImportResource: 导入其他XML配置文件
@Bean: 在方法上使用,声明此方法为一个Bean
简单使用
import java.util.ArrayList;
import java.util.LinkedList;
import org.springframework.beans.factory.support.BeanDeFinitionBuilder;
import org.springframework.beans.factory.support.BeanDeFinitionRegistry;
import org.springframework.beans.factory.support.DefaultListablebeanfactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClasspostProcessor;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDeFinitionRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class TestConfiguration {
public static void main(String[] args) {
DefaultListablebeanfactory beanfactory = new DefaultListablebeanfactory();
BeanDeFinitionBuilder builder = BeanDeFinitionBuilder
.genericBeanDeFinition(BeanConfig.class);
//注册BeanConfig类
beanfactory.registerBeanDeFinition("beanConfig", builder.getBeanDeFinition());
//处理@Configuration注解
ConfigurationClasspostProcessor configurationClasspostProcessor = new ConfigurationClasspostProcessor();
configurationClasspostProcessor.postProcessBeanDeFinitionRegistry(beanfactory);
configurationClasspostProcessor.postProcessbeanfactory(beanfactory);
System.out.println(beanfactory.getBean("beanConfig").getClass());
System.out.println(beanfactory.getBean("myArrayList").getClass());
System.out.println(beanfactory.getBean(LinkedList.class).getClass());
}
@Configuration(proxyBeanMethods = true)
@ComponentScan
@Import({MyBeanRegistrar.class, MySelector.class})
public static class BeanConfig {
}
public static class MyBeanRegistrar implements ImportBeanDeFinitionRegistrar {
@Override
public void registerBeanDeFinitions(AnnotationMetadata importingClassMetadata,
BeanDeFinitionRegistry registry) {
BeanDeFinitionBuilder builder = BeanDeFinitionBuilder
.genericBeanDeFinition(ArrayList.class);
registry.registerBeanDeFinition("myArrayList", builder.getBeanDeFinition());
}
}
public static class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{LinkedList.class.getName()};
}
}
}
这里为了更好的分析原理,没有使用更加强大的ApplicationContext,核心类为ConfigurationClasspostProcessor,
这是一个BeanDeFinitionRegistryPostProcessor(BeanDeFinitionRegistry后置处理器,可以让对BeanDeFinitionRegistry进行扩展处理,如添加自定义的BeanDeFinition),
也是一个beanfactoryPostProcessor(beanfactory后置处理器,可以让我们扩展beanfactory)。
ConfigurationClasspostProcessor会判断Bean是否为一个配置类,如果是,就解析此类,具体就是解析@ComponentScan,@Import等注解。
如果我们使用支持JavaConfig的ApplicationContext,它会通过AnnotationConfigUtils的registerannotationConfigProcessors()方法来自动添加ConfigurationClasspostProcessor类。
ApplicationContext会在refresh()方法执行过程中处理ConfigurationClasspostProcessor的后置方法,
关于ApplicationContext,可以查看Spring源码分析之ApplicationContext 。
源码分析
在Spring源码分析之ApplicationContext 的基础上,我们可以知道,在refresh()方法的步骤invokebeanfactoryPostProcessors()中,
会执行BeanDeFinitionRegistryPostProcessor的postProcessBeanDeFinitionRegistry()方法,
然后再执行beanfactoryPostProcessor的postProcessbeanfactory()方法,所以我们先分析ConfigurationClasspostProcessor的postProcessBeanDeFinitionRegistry()方法。
postProcessBeanDeFinitionRegistry
@Override
public void postProcessBeanDeFinitionRegistry(BeanDeFinitionRegistry registry) {
//处理配置
processConfigBeanDeFinitions(registry);
}
继续跟进去
public void processConfigBeanDeFinitions(BeanDeFinitionRegistry registry) {
List<BeanDeFinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDeFinitionNames();
//过滤出所有Bean中为配置类的Bean,下面会说判断的条件
for (String beanName : candidateNames) {
BeanDeFinition beanDef = registry.getBeanDeFinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONfigURATION_CLASS_ATTRIBUTE) != null) {
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.MetadataReaderFactory)) {
configCandidates.add(new BeanDeFinitionHolder(beanDef, beanName));
}
}
//没有配置类
if (configCandidates.isEmpty()) {
return;
}
//按照优先级排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getorder(bd1.getBeanDeFinition());
int i2 = ConfigurationClassUtils.getorder(bd2.getBeanDeFinition());
return Integer.compare(i1, i2);
});
//从容器中查找Bean名称生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONfigURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
//创建environment
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
//配置类解析器
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 {
//真正开始解析
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());
}
//从解析好的配置类中加载BeanDeFinition,注册到容器中
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());
}
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());
//将ImportRegistry注册为一个Bean,用来支持ImportAware钩子回调
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
判断一个Bean为配置类的逻辑为
- 判断Class是否包含@Configuration注解,如果包含,为配置类
- 如果没有,@Component,@ComponentScan,@Import,@ImportResource,查看是否包含此4个注解之一,如果包含,为配置类
- 如果没有,判断Class是否有方法包含@Bean注解
上述逻辑汇总,核心地方有两个,一个是解析配置类,一个是加载配置类,先看解析,进入ConfigurationClassparser解析器
public void parse(Set<BeanDeFinitionHolder> configCandidates) {
for (BeanDeFinitionHolder holder : configCandidates) {
BeanDeFinition bd = holder.getBeanDeFinition();
try {
//根据不同的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());
}
}
}
//这个处理也是很重要的,延迟导入,SpringBoot提供的AutoConfigurationImportSelector就是一个延迟加载的导入选择器,
//它会在我们我们自己的配置类加载之后再加载,相当于低优先级,
//因为在处理OnMissingBeanCondition等注解时需要依赖前面的配置类来判断某个Bean是否已经在容器中存在
this.deferredImportSelectorHandler.process();
}
不同的BeanDeFinition类型,都会统一创建一个ConfigurationClass来处理,继续跟进去
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//处理@Conditional注解,根据条件判断该配置类是否需要被加载
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONfigURATION)) {
return;
}
//处理已经解析过的情况
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
this.configurationClasses.remove(configClass);
this.kNownSuperclasses.values().removeIf(configClass::equals);
}
}
//递归处理配置类及父类
SourceClass sourceClass = asSourceClass(configClass);
do {
//核心,解析配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
开始真正的处理解析配置类
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
//处理内部类的情况
processMemberClasses(configClass, sourceClass);
}
//解析@PropertySource注解,用来处理properties文件,添加到environment中
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processpropertySource(propertySource);
}
}
//解析@ComponentScan注解
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) {
//内部使用ClasspathBeanDeFinitionScanner扫描器,默认扫描@Component注解,注意,扫描完成已经将BeanDeFinition注册到容器中了
Set<BeanDeFinitionHolder> scannedBeanDeFinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//如果扫描到的BeanDeFinition也包含配置类,递归解析配置类
for (BeanDeFinitionHolder holder : scannedBeanDeFinitions) {
BeanDeFinition bdCand = holder.getBeanDeFinition().getoriginatingBeanDeFinition();
if (bdCand == null) {
bdCand = holder.getBeanDeFinition();
}
//判断是否为配置类
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.MetadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//解析@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), true);
//解析@ImportResource注解,可以导入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);
}
}
//解析包含@Bean注解的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//处理接口相关,不用管
processInterfaces(configClass, 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();
}
}
//没有父类,处理结束
return null;
}
关于解析@Import注解,此注解配置的类型可以有三种:
- ImportSelector接口类型,可以看做一个导入选择器,返回多个要导入的Class类型,如SpringBoot自动装配的实现AutoConfigurationImportSelector。
- ImportBeanDeFinitionRegistrar,可以看做一个注册器,Spring提供的一个钩子,可以让我们向BeanDeFinitionRegistry中添加自定义的BeanDeFinition,
如开启AOP的AspectJAutoproxyRegistrar。 - 其他类型的配置类
接下来继续分析配置类的加载,进入ConfigurationClassBeanDeFinitionReader的loadBeanDeFinitions()方法
public void loadBeanDeFinitions(Set<ConfigurationClass> configurationModel) {
//使用一个支持追踪的条件解析器来判断配置类是否可以加载,如果A配置类是被B配置类通过@Import注解引入的,B配置类不加载,那么A配置类也不能被加载
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;
}
//如果此配置类是被导入的,注册此配置类到容器中
if (configClass.isImported()) {
registerBeanDeFinitionForImportedConfigurationClass(configClass);
}
//注册所有包含@Bean注解的方法到容器中,这种Bean通过工厂方法来实例化
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDeFinitionsForBeanMethod(beanMethod);
}
//使用XmlBeanDeFinitionReader从XML配置文件中加载所有Bean,其实还支持groovy类型的配置文件,用的不多,就先不管了
loadBeanDeFinitionsFromImportedResources(configClass.getImportedResources());
//从注册器加载,依次调用所有ImportBeanDeFinitionRegistrar的registerBeanDeFinitions()方法
loadBeanDeFinitionsFromregistrars(configClass.getImportBeanDeFinitionRegistrars());
}
至此Spring已经将所有的BeanDeFinition都注册到容器中了。
postProcessbeanfactory
@Override
public void postProcessbeanfactory(ConfigurableListablebeanfactory beanfactory) {
//使用cglib对配置类创建动态代理
enhanceConfigurationClasses(beanfactory);
beanfactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanfactory));
}
通过@Configuration(proxyBeanMethods = true)
来标记开启代理,默认就是true,主要是为了处理下面这种情况
@Configuration(proxyBeanMethods = true)
public static class BeanConfig {
@Bean("myHashSet")
public Set<String> myHashSet() {
return new HashSet<>();
}
@Bean("myArrayList")
public List<String> myArrayList() {
return new ArrayList<>(myHashSet());
}
@Bean("myLinkedList")
public List<String> myLinkedList() {
return new LinkedList<>(myHashSet());
}
}
在配置类中声明了3个Bean,按理来说只会创建一个名称为myHashSet的Bean,但myArrayList()和myLinkedList方法内部都调用了myHashSet()方法,不能创建两个myHashSet的Bean,
这就是因为Spring对配置类创建了动态代理对象,当调用myHashSet()方法时,会根据方法找到对应的Bean名称,从容器中查询出对应的Bean对象。
分析总结
Spring处理配置主要有以下几个类:
- ConfigurationClasspostProcessor: 框架类,使用下面的几个类来完成解析,加载
- ConfigurationClassparser: 解析所有配置类
- ConfigurationClassBeanDeFinitionReader: 加载所有配置类
- ConfigurationClassEnhancer: 根据需要对配置类创建代理
Spring框架的核心有两个:
- 注册BeanDeFinition到容器中
从各种渠道注册,如XML配置文件,@Component注解,@Bean注解,手动创建BeanDeFinition注册,各种扩展类如ImportBeanDeFinitionRegistrar的注册。 - 根据BeanDeFinition创建Bean对象
创建过程中,可能会创建代理对象,这就是AOP的功能。
Spring很多附加的功能都是通过帮我们自动注册了很多BeanDeFinition来完成的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。