Springboot自动装配源码分析
概要
在spring中,使用xml的方式将定义的bean加载到ioc容器中是最原始的定义方式,3.x 后,支持注解来加载bean。spring注解的方式总结下来只要有以下几种:
Configration
+ComponentScan
配置在配置类中,然后需要定义的bean,在类上加上Controller、Service、Component
等注解
@Configuration
@ComponentScan({"anno"})
public class ParentScan {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ParentScan.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
}
// 其中Service1类如下
@Service
public class Service1 {
public void go(){
System.out.println("service1 .....");
}
}
- 使用
Configration
注解,同时在配置类中使用Bean
注解定义bean
@Configuration
public class BeanScan {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScan.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
@Bean
Service1 service1(){
return new Service1();
}
}
Configration
+Import
,其中Import
可以是配置类,也可以是普通类
@Configuration
@Import(ParentScan.class)
public class ImportConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportConfig.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
}
@Configuration
@ComponentScan({"anno"})
public class ParentScan {
}
@Configuration
@Import({Service1.class})
public class ImportBean {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportBean.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
}
Configration
+Import
+ImportSelector
的方式
@Configuration
@Import(MySelector.class)
public class ImportSelector {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportSelector.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
}
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
Service1.class.getName()
};
}
}
- 还可以采用自定义注解
EnableXXX
的方式
@Configuration
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableMySelector {
}
@EnableMySelector
public class MyEnable {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyEnable.class);
Service1 service1 = context.getBean(Service1.class);
service1.go();
}
}
在测试用例中,用到的ApplicationContext
实现类是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
其类关系图:
在ioc容器的处理过程,后置处理器org.springframework.context.annotation.ConfigurationClassPostProcessor
会加载处理到带有@Configuration
注解的类
@SpringBootApplication
@Target(ElementType.TYPE)//该注解只能声明在一个类前
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Documented//表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的
@Inherited//表示该注解会被子类继承
@SpringBootConfiguration// ===> 继承自@Configuration,二者功能也一致,标注当前类是配置类
@EnableAutoConfiguration//===> 自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**排除指定的自动装配的类型
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**排除指定的自动装配的类型
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};//扫描指定的包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};//扫描指定包中的类
//指定 bean 名称生成器
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
//配置 @Bean 注解的方法返回的 bean 是否需要被代理,默认为 true,需要被代理。使用 CGLIB 增强代理
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented// 表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的
@Inherited//表示该注解会被子类继
@AutoConfigurationPackage// ===> 自动配置包, 作用:将main包下的所组件注册到容器中
//@Import的作用就是导入一个类到IOC容器
@Import(AutoConfigurationImportSelector.class)// ===> 核心AutoConfigurationImportSelector的方法selectImports
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
在这个注解下我们需要关注两个注解@AutoConfigurationPackage
·,@Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//new PackageImports(metadata).getPackageNames()返回一个主包名称
//这个包就是Spring Boot主配置类所在的包,metadata,返回主配置类
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//如果存在这个bean定义
if (registry.containsBeanDefinition(BEAN)) {
BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
} else {
//不存在就注册(在这个package路径下的org.springframework.boot.tests.hibernate52)
registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
}
}
@Import({AutoConfigurationImportSelector.class}
关键方法:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
//getAutoConfigurationEntry()方法返回所有带有@Configuration注解的类的全类名,
//Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取到这个数组,
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//发现configurations的结果是所有的xxxAtuoConfiguration类,配置类一共124个
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // ===> 这里!
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes); // ===> 排除哪些
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions); // 排除掉
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions); // 封装起来,返回去
}
此处是去获取真正自动配置类的集合
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//打开spring-boot-autoconfigure/META-INF/spring.factories
//132个,随便选一个进去看看
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader()); // ===> loadFactoryNames , getSpringFactoriesLoaderFactoryClass
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations; //返回需要加载的 Configration 类的名字
}
其中的org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
方法,最终会去加载spring-boot-autoconfigure
中的spring.factories
文件
注意的是,在代码中加载的时候并不是全部加载这些配置类,而是根据bean的加载条件进行加载,这时候@ConditionalOnxxx
注解发挥作用了。
原文地址:https://blog.csdn.net/weixin_42612223/article/details/140639185
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!