首先我们知道启动类的注解SpringBootApplication
点进去后会看到boot 的核心三大注解

java自定义注解比较简单
https://blog.youkuaiyun.com/crazyo2jam/article/details/103486320
三大注解
@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
其内部我们可以看出主要以@Configuration作为主体,也就是声明为spring容器注入组件的意思
@EnableAutoConfiguration
最最最核心的"自动装配"注解 我们点进去
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
我们可以看到
@AutoConfigurationPackage.
@Import({AutoConfigurationImportSelector.class})// 导入组件
在内部有一个方法selectImports返回是一个数组,通过全类名+反射的机制实例化纳入到spring容器中使用,

我们在点入this.getAutoConfigurationEntry看一下
加载工厂名称

加载spring工厂

自动加载文件

文件在这里

值是map形式的kv值,会自动装配配置内的类,以String数组的形式返回,通过全类名+反射的方式进行实例化

那么每个类都要去装配吗???
我们点进一个类看一下这个装配的类具有一定的装配条件

我们在application.properties 写入debug=true
我们会看到
Positive matches:
----------------- 已经加载装配的
AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
- 一堆就不一一写了
Negative matches:
----------------- 未符合要求未装配的
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
- - 一堆就不一一写了
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class ‘javax.jms.ConnectionFactory’ (OnClassCondition)
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean),该注解的参数对应的类必须存在,否则不解析该注解修饰的配置类;
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean), 该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean;可以给该注解传入参数例如@ConditionOnMissingBean(name = “example”),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行。
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)
@ConditionalOnProperty是指在application.yml里配置的属性是否为true,其他的几个都是对class的判断
我们再来看@AutoConfigurationPackage内有一个@Import({Registrar.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import({Registrar.class}) 点入注册类
这是批量的讲类注册为bean的实现方发因为实现了ImportBeanDefinitionRegistrar接口
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
那么是怎么回事那,源码中太乱我们自己简单的测试下
新建一个实体类student 实现类MyImportBean
1.实体类student 实现类MyImportBean实现ImportBeanDefinitionRegistrar
2.重写ImportBeanDefinitionRegistrar的两个方法
@Component //声明是个组件类
public class MyImportBean implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
//BeanDefinitionRegistry bean的定义注册 可以是现在运行期间动态绑定到容器中
//通过BeanDefinition构造出Student 的定义
BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
//bean 有个 id 和class类型 参1就是bean的id 参2是注入的哪个bean
for(int i=0;i<10;i++){//生成10个bean
registry.registerBeanDefinition("stu"+i,beanDefinition);
System.out.println("生成="+i);
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//一定要写在上一个方法里(3个参数的)
}
}
3在resources目录下新建META-INF目录创建文件spring.factories
(想当于在执行application.yml前执行spring.factories,也同等于了springboot注解内的功能)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.demo.config.MyImportBean
4启动类
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run=SpringApplication.run(SpringbootApplication.class, args);
System.out.println(run.getBeansOfType(Student.class));
}
}
打印得出
生成=0
生成=1
生成=2
生成=3
生成=4
生成=5
生成=6
生成=7
生成=8
生成=9
2019-12-11 11:17:31.326 INFO 16352 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-12-11 11:17:31.333 INFO 16352 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-12-11 11:17:31.334 INFO 16352 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29]
2019-12-11 11:17:31.407 INFO 16352 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-12-11 11:17:31.407 INFO 16352 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 820 ms
2019-12-11 11:17:31.531 INFO 16352 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-12-11 11:17:31.653 INFO 16352 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-12-11 11:17:31.655 INFO 16352 --- [ main] cn.demo.SpringbootApplication : Started SpringbootApplication in 1.461 seconds (JVM running for 2.96)
{stu0=cn.demo.pojo.Student@61a1ea2c, stu1=cn.demo.pojo.Student@149debbb, stu2=cn.demo.pojo.Student@25cd49a4, stu3=cn.demo.pojo.Student@5477a1ca, stu4=cn.demo.pojo.Student@3ae9d1e2, stu5=cn.demo.pojo.Student@41522537,
stu6=cn.demo.pojo.Student@e9dc4d0, stu7=cn.demo.pojo.Student@670d4d38, stu8=cn.demo.pojo.Student@131ff6fa, stu9=cn.demo.pojo.Student@43b40233}
方法2 通过全类型注册
@Component //声明是个组件类
public class MyImportBean2 implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"cn.demo.pojo.Student","cn.demo.pojo,Root"};
}
}
配置文件----
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.demo.config.MyImportBean,cn.demo.\
config.MyImportBean
##大致总结一下
AutoConfigurationImportSelector是导入组件选择器
讲所有需要导入的组件以全类名的方式返回;组件被添加到容器中;会给容器中导入非常多的自动配置类(XXXAutoConfiguration)
springboot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将值作为自动导入容器中,整合方案都在spring-boot-autoConfiguration-2.1.6,jar中
@ComponentScan(
扫描类的注解,根据注解进行装配

本文深入解析Spring Boot启动过程,详细阐述@SpringBootApplication注解的作用,包括自动配置、组件扫描等核心功能,以及如何通过自定义注解实现组件的动态注册。
805

被折叠的 条评论
为什么被折叠?



