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都会被读取。