@Configuration注解与@Component注解的区别,@Component注解用来定义一个Bean,而@Configuration与@Bean注解结合,可以在一个类中定义多个Bean。
spring会扫描所有@component注解的类及其子类(包括@Configuration注解声明的类),认为这些类是bean, 并且把这些bean对应的beanDefinition放到容器中进行管理。BeanDefinition是对bean的描述,里边存有bean的名称,Class等基本信息
在获取到所有的bean defenition之后,Spring会有一些post process执行,其中一个就是ConfigurationClassPostProcessor, 在这里,Spring会遍历所有的bean definition, 如果发现其中有标记了@Configuration注解的,会对这个类进行CGLIB代码,生成一个代理的类,并且把这个类设置到BeanDefenition的Class属性中。当需要拿到这个bean的实例的时候,会从这个class属性中拿到的Class对象进行反射,那么最终反射出来的是代理增强后的类
代理中对方法进行了增强?在哪方面进行了增强?对于@Bean标记的方法,返回的都是一个bean,在增强的方法中,Spring会先去容器中查看一下是否有这个bean的实例了,如果有了的话,就返回已有对象,没有的话就创建一个,然后放到容器中。
Full模式
标注有@Configuration或者@Configuration(proxyBeanMethods = true)的类被称为Full模式的配置类。
@Configuration注解标记的类是配置类,Bean定义信息被标记为full 类型。
@Configuration
public class FullConfig {
@Bean
public User userA() {
User user = new User();
user.setName("userA");
return user;
}
@Bean
public User userB() {
User user = new User();
user.setName("userB");
//full模式下:调用userA()多少次都是返回容器中注入的同一个Bean
System.out.println("userB1:"+System.identityHashCode(userA()));
System.out.println("userB2:"+System.identityHashCode(userA()));
System.out.println("userB3:"+(userA()== userA())); //true
return user;
}
private static class InnerConfig {
@Bean
public final User userInner() {
User user = new User();
user.setName("userInner");
return user;
}
}
}
- 该模式下,配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理。
- 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式。
- 该模式下,配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例。
- 该模式下,@Bean方法不能被private/final等进行修饰(很简单,因为方法需要被复写嘛,所以不能私有和final。
优点:可以支持通过常规Java调用相同类的@Bean方法而保证是容器内的Bean,这有效规避了在“Lite模式”下操作时难以跟踪的细微错误。特别对于萌新程序员,这个特点很有意义。
缺点:运行时会给该类生成一个CGLIB子类放进容器,有一定的性能、时间开销(这个开销在Spring Boot这种拥有大量配置类的情况下是不容忽视的,这也是为何Spring 5.2新增了proxyBeanMethods属性的最直接原因);正因为被代理了,所以@Bean方法 不可以是private、不可以是final。
Lite(精简)模式
- @Configuration(proxyBeanMethods = false)为lite 模式。
当@Bean方法在没有使用@Configuration注释的类中声明时,它们被称为在Lite模式下处理。它包括:在@Component中声明的@Bean方法,甚至只是在一个非常普通的类中声明的Bean方法,都被认为是Lite版的配置类。@Bean方法是一种通用的工厂方法(factory-method)机制。
和Full模式的@Configuration不同,Lite模式的@Bean方法不能声明Bean之间的依赖关系。因此,这样的@Bean方法不应该调用其他@Bean方法。
有如下case均认为是Lite模式的配置类:
- 类上标注有@Component注解。
- 类上标注有@ComponentScan注解。
- 类上标注有@Import注解。
- 类上标注有@ImportResource注解。
- 若类上没有任何注解,但类内存在@Bean方法。
- 标注有@Configuration(proxyBeanMethods = false),注意:此值默认是true哦,需要显示改为false才算是Lite模式(Spring 5.2之后)。
- 该模式下,配置类本身不会被CGLIB增强,放进IoC容器内的就是类本身。
- 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式。
- 该模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例。
- 该模式下,配置类就是一普通类,所以@Bean方法可以使用private/final等进行修饰。
@Component //lite模式
public class LiteConfig {
@Bean
public Student stuA() {
Student stu= new Student ();
stu.setName("stuA");
return stu;
}
@Bean
private Student stuB() { //可以是private的方法
Student stu= new Student ();
stu.setName("stuB");
//lite模式下:调用stuA()方法会生成一个新的Bean
System.out.println("stuB1:"+System.identityHashCode(stuA()));
System.out.println("stuB2:"+System.identityHashCode(stuA()));
System.out.println("stuB3:"+(userA()== userA())); //返回false
return stu;
}
//内部类可以是任意模式
private static class InnerConfig {
@Bean
//lit模式下方法可以使用private final修饰
private final Student stuInner() {
Student stu= new Student ();
stu.setName("stuInner");
return stu;
}
}
}
解析配置类
ConfigurationClassParser.parse():
// 服务启动时:configCandidates代表启动类
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
...
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 以上根据启动类处理完自定义类(加入到Map中configurationClasses)
processDeferredImportSelectors();// 会加载启动类中EnableAutoConfiguration注解的类,或者factory.properties中的配置类
}
ConfigurationClassPostProcessor#processConfigBeanDefinitions()
ConfigurationClassParser.processConfigurationClass
ConfigurationClass:DataSourceAutoConfiguration
importedBy表明该配置类是在解析启动类时发生的。
annotatedMethods:表示该配置类存在的方法
//ConfigurationClass:
//Represents a user-defined {@link Configuration @Configuration} class.
//Includes a set of {@link Bean} methods, including all such methods
//defined in the ancestry of the class, in a 'flattened-out' manner.
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 判断当前类是否需要实例化
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
...
// 通过metaData中className属性生成该配置类的类信息 sourceClass(DataSourceAutoConfiguration)
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
// 将处理完的当前类放到类ConfigurationClassParser Map属性configurationClasses中
this.configurationClasses.put(configClass, configClass);
}
扫描启动类包下所有应用自定义类
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
...
// 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) {
// 通过启动类包路径 basePackages 扫描得到所有的类信息
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
// 依次处理 scannedBeanDefinitions 中扫描的类
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 检查当前类是否是Configuration注解下的 full or lite 模式
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 递归每个类中的所有注解(@PropertySource、@ComponentScan、@Import、@ImportResource)
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
...
// No superclass -> processing is complete
return null;
}
判断 Configuration 注解是否为 full 模式 or lite 模式:
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
...
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
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;
}
处理启动类中注解EnableAutoConfiguration标识的类
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
if (deferredImports == null) {
return;
}
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
(group == null ? deferredImport : group),
(key) -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
for (DeferredImportSelectorGrouping grouping : groupings.values()) {
// 获取factory.properties文件中的配置类
grouping.getImports().forEach((entry) -> {
ConfigurationClass configurationClass = configurationClasses.get(
entry.getMetadata());
try {
// 解析 factory.properties文件中存在的每个配置类
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
...
});
}
}
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 {
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 (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
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 如果factory.properties中配置类没有ImportSelector or ImportBeanDefinitionRegistrar注解,就当普通配置类处理,最终存放到configurationClasses中
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
...
finally {
this.importStack.pop();
}
}
}
SpringBoot中候选类为配置类的标准
abstract class ConfigurationClassUtils {
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());
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
if (metadata.isInterface()) {
return false;
}
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
}