1 预备知识
1.1 Bean扫描
注解@ComponentScan
,默认扫描启动类所在包及其子包。
想要自定义可以修改注解参数,例如@ComponentScan(baesePackages = 'com.henry')
。
1.2 Bean注册
需要注册的bean是自定义,使用以下注解注册bean对象。
注解
说明
位置
@Component
声明bean的基础注解
不属于以下三类时,用此注解
@Controller
@Component的衍生注解
标注在控制器类上
@Service
@Component的衍生注解
标注在业务类上
@Repository
@Component的衍生注解
标注在数据访问类上(由于与mybatis整合,用的少)
如果要注册的bean对象来自于第三方,使用下面两个注解
示例:
1
2
3
4
5
6
7
@Configuration
public class config {
@Bean //默认名是方法名
public Country country () {
return new Country ();
}
}
假设上面写的config.java
不在启动类所在包及其子包,那么可以使用import
注解进行bean的注册。
1
2
3
4
5
6
7
@SpringBootApplication
@Import ( config . class ) //默认名是全类名
public class xxxApplication {
public static void main ( String [] args ) {
xxxApplication . run ( xxxApplication . class , args );
}
}
此时会将config
放入ioc容器,并将config
中声明的bean
也注册到ioc容器。
同时,import可以导入多个配置类,一种是@Import({config.class, xx.class})
,或者导入ImportSelector
的接口实现类,接口实现类要实现selectImports
方法,在方法内部返回数组,数组内容为要导入的Bean对象的全类名。第二种方法示例如下:
1
2
3
4
5
6
public class CommonImportSelector implements ImportSelector {
@Override
public String [] selectImports ( AnnotationMetadata importingClassMetadata ) {
return new String []{ "com.itheima.config.CommonConfig" };
}
}
1.3 Bean管理
注解
说明
@ConditionalOnProperty
配置文件中存在对应的属性,才声明该bean
@ConditionalOnMissingBean
当不存在当前类型的bean时,才声明该bean
@ConditionalOnClass
当前环境存在指定的这个类时,才声明该bean
2 源码解读
Springboot注解包含以下注解@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
三个核心注解。
1
2
3
4
5
@ ...
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan (...)
public @interface SpringBootApplication {
@EnableAutoConfiguration注解
包括了@Import({AutoConfigurationImportSelector.class})
注解。该注解导入ImportSelector
的接口实现类。
1
2
3
@Import ({ AutoConfigurationImportSelector . class })
public @interface EnableAutoConfiguration {
}
该类重写了selectImports
方法,调用过程指向getAutoConfigurationEntry
。
1
2
3
4
5
6
7
public String [] selectImports ( AnnotationMetadata annotationMetadata ) {
if (! this . isEnabled ( annotationMetadata )) {
return NO_IMPORTS ;
} else {
AutoConfigurationEntry autoConfigurationEntry = this . getAutoConfigurationEntry ( annotationMetadata ); return StringUtils . toStringArray ( autoConfigurationEntry . getConfigurations ());
}
}
getAutoConfigurationEntry
,显然configurations
来自于getCandidateConfigurations
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected AutoConfigurationEntry getAutoConfigurationEntry ( AnnotationMetadata annotationMetadata ) {
if (! this . isEnabled ( annotationMetadata )) {
return EMPTY_ENTRY ;
} else {
AnnotationAttributes attributes = this . getAttributes ( annotationMetadata );
List < String > configurations = this . getCandidateConfigurations ( annotationMetadata , attributes );
configurations = this . removeDuplicates ( configurations );
Set < String > exclusions = this . getExclusions ( annotationMetadata , attributes );
this . checkExcludedClasses ( configurations , exclusions );
configurations . removeAll ( exclusions );
configurations = this . getConfigurationClassFilter (). filter ( configurations );
this . fireAutoConfigurationImportEvents ( configurations , exclusions );
return new AutoConfigurationEntry ( configurations , exclusions );
}
}
getCandidateConfigurations
,本方法中出现META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
路径。
1
2
3
4
5
6
protected List < String > getCandidateConfigurations ( AnnotationMetadata metadata , AnnotationAttributes attributes ) {
List < String > configurations = new ArrayList ( SpringFactoriesLoader . loadFactoryNames ( this . getSpringFactoriesLoaderFactoryClass (), this . getBeanClassLoader ()));
ImportCandidates . load ( AutoConfiguration . class , this . getBeanClassLoader ()). forEach ( configurations :: add );
Assert . notEmpty ( configurations , "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct." );
return configurations ;
}
该路径中存在所有需要导入的自动配置类。在springboot-starter
(该starter
为所有starter
的starter
)导入的spring-boot-autoconfigure
的INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
路径中存在org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
类。以该类为例继续分析。
1
2
3
4
5
6
@AutoConfiguration
public class WebMvcAutoConfiguration {
@EnableConfigurationProperties ({ WebProperties . class })
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
xxx ;
}
该配置类注册了多个bean,EnableWebMvcConfiguration
与WebProperties.class
绑定,该类中@EnableConfigurationProperties
注解可以将@ConfigurationProperties(prefix = "spring.mvc")
注解所在类注入。因为即使加了@Component
注解在Properties文件下该类依旧无法被扫描,所以采用@EnableConfigurationProperties
注解绑定。
1
2
3
@ConfigurationProperties ( prefix = "spring.mvc" )
public class WebMvcProperties {
}
此外,经实验测试,类路径下所有的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
都会被读取。