2021-09-10 SpringBoot 自动配置

1.spring的版本进化特点

1.1SPRING框架1.X版本

开发人员大量编写xml配置文件,大量的bean标签的使用,实现set注入,构造方法注入等。

1.2SPRING框架2.X版本

转折:java出现了java5(jdk1.5)。出现新特性反射,枚举,注解。

spring转型:将xml中编写的配置文件,转向注解来开发,@Controller @Repository @Service @Component @Autowired。

开发习惯:允许开发人员将自定义的业务代码从xml转向代码注解。减少了xml编配内容。

但是第三方的一些内容,还是需要xml配置支持。例如Datasource 实现类ComboPooledDatasource。

注解+xml配置这种格式,出现最多的环境是spring2.x

1.3SPRING框架3.X版本

继续扩展注解,出现了一批新功能注解@Configuration @Bean @ComponetScan @Import等。

致力于将2.x中残存的那些配置xml逻辑,完全转向代码配置。

趋势:xml即将消失

1.4SPRING框架4.X/5.X版本

4.x出现了条件注解@Conditional.允许在将xml转向代码的同时,利用条件实现各种代码加载的逻辑。比如何时加载,何种条件满足下加载,何种条件不满足时加载

--springboot在条件注解的基础上,扩展了衍生了大量的条件子注解@ConditionalOnClass,实现了最终走向自动配置的全部准备——

5.X已经没有了xml约束文件。

 

2.spring3.X的重要注解

2.1@Confugration

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

类注解 ElementType.TYPE

运行时 RUNTIME加载

@Component 继承了@Component特性:类上加载这个注解,至少这个类在容器中一旦被扫描就可以创建bean对象。

  • 作用:将一个类标识为一个配置类,等同于之前一个xml文件的位置。可以使用一个类,来代替xml使用
  • 案例1:bean标签加载,和@Bean注解
    • 加载xml的方式
      • 准备xml

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 配置一个bean标签

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 准备bean对象类

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 测试代码,加载xml创建容器

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 加载配置类
    • 准备一个配置类,使用@Configuration注解

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 使用加载配置类的方式启动容器

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • @Bean配合@Configuration

代替之前xml编写格式,bean标签。代码底层原理是工厂bean加载。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 案例2:component-scan 和@ComponentScan注解
    • xml加载
      • 修改xml配置文件

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

在xml中开启包扫描,扫描cn.tedu.bean

  • 编写一个新的类Bean2

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

最终容器启动,bean2也创建。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 配置类加载
    • 修改配置类添加@ComponentScan注解

使用xml的扫描标签,将被扫描到的@Component注解所在类的bean对象创建到容器里,同样的配置类起到xml作用,也可以实现这个功能,需要使用一个注解@ComponentScan。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 加载效果相同

bean1 bean2都出现了

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • import标签

使用xml配置的结构中,可以将大量的配置逻辑标签,存放到一个xml配置文件的,但是为了方便维护,一般会区分不同技术,引入多个xml,最终让容器加载。

  • 添加配置文件xml

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 编写新类Bean3

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

加载ac1.xml就没有ac2.xml的功能,反过来加载也一样,如何实现2个都加载呢?可以使用import标签。加载ac1.xml同时,导入性的读取ac2.xml

  • 使用import标签

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 容器运行

加载的还是原有ac1.xml,通过import标签实现ac2.xml同时加载。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 配置类@Import注解

如果配置类可以代替xml使用,他也可以导入其他配置类。

  • 准备新的配置类

用这个配置类代替ac2.xml配置文件。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

最终加载的还是第一个配置类MyConfiguration01,可以使用@Import注解从配置类导入其他配置类。实现和import标签相同的效果。

  • 修改加载的配置类MyConfiguration01

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 最终效果

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

  • 模拟想象一个springboot场景

springboot提前准备扩展了非常多的常见应用场景对应的配置类,代替原有手动编写的xml,比如datasource配置,mybatis的配置,redis配置。

只要要求我们使用时,准备一个注解@Import将他所编写的大量底层实现配置逻辑加载。就可以实现自动配置了。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

分析:

我得有自己的配置类作为入口。

还得找到springboot给我提供的配置类。

还得找到我的配置import导入他的配置的线索。

3.SPRINGBOOT核心注解

启动类中添加的@SpringBootApplication

3.1观察原码

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

组合了三个注解

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan

组合注解:注解通过继承组合的方式,可以同时具备多个注解的功能

3.2SpringBootConfiguration

他的原码

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

这个注解本身就是表示配置类注解@Configuration,有他在的类就是配置类。启动类添加这个注解之后,就变成了一个配置类。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

其中run方法就包含了测试案例中启动spring容器,加载配置类的功能。返回对象就是容器上下文。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

3.3SPRINGBOOT自动配置类

在当前libaray库中,可以找到org.springframework.boot.autoconfigure的jar包,这里包含了springboot当前版本提供的所有自动配置类代码。从中可以找到大量的**AutoConfiguration,目前2.2.5.RELEASE版本存在直接的226个自动配置类,间接加载的配置上千个。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

3.4@EnableAutoConfiguration

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

这个注解也是核心注解,在启动类上添加的一个组合注解之一。作用主要是从我们的启动类加载springboot的自动配置类。所以你一旦启动springboot,就会完成他底层大量自动配置类的加载过程

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

**理解selector

@Import不光导入可以单个指定名字的配置类。

还可以批量导入,需要配置的是一个selector选择器,选择器会加载当前环境中一个spring.factories中所有自动配置类的全路径名称,返回的是String[] 从中拿到配置类最终加载

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。
 

 

4.条件注解和衍生注解

4.1条件注解@Conditional

spring4.x版本出现的

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

有一个关键属性 value 值是Condition条件类的反射对象。我们可以利用这个类的实现逻辑来完成非常多种的条件判断。

例如:

与poroperties属性有关的条件

根据某个key的存在或者不存在判断

根据某个前缀的key值存在或者不存在判断

与class类有关的条件

根据依赖中存在哪个class判断

根据依赖中必须不存在哪个class判断

。。。

4.2springboot条件的衍生注解

springboot在开发过程中,根据conditional的功能早就实现了非常多种的衍生注解

  • @ConditionalOnClass

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

这个注解是类注解,和方法注解,在一个配置类中,这个注解的存在会使容器加载配置类的时候判断条件是否满足,当某个特定的class类存在于依赖中才会加载这个类或者方法。

4.3案例演示

使用容器加载一个配置类,这个配置类使用了条件注解ConditionalOnClass,满足条件,才加载,不满足就不加载,容器中根本不理会这个配置类。

  • 添加一个条件注解的配置类

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

 

当前是一个配置类,但是由于条件注解的存在,要求classpath环境必须有一个依赖类ConditionA存在才能满足条件,如果不满足,类是存在,则不加载这个配置类

  • 扫描该配置类所在包

MyConfiguration01中扫描他

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

  • 启动运行

idea不允许默认情况下在编译有问题时运行代码。修改启动配置

运行结果,由于conditionA类不存在,所以条件满足,

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

如果换一个条件使用CondionB当条件内容,然后在当前项目准备这个类。由于条件不满足,配置类不加载。

 

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

4.4其他衍生注解

@ConditionalOnBean:类和方法注解,当环境中存在某个类的容器bean对象时满足条件,当前配置类,或者方法就加载执行,反之不加载。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

@ConditionalOnMissingBean

@ConditionalOnProperty:可以实现对特定属性特定值的判断,可以从存在不存在,前缀满足,包含某个值的角度,等于某个值,不等于某个值的角度实现条件的判断

@ConditionalOnWebApplication:当前容器必须是web应用,判断有没有servlet容器启动

@ConditionalOnNotWebApplication:当前容器必须不能是web应用,没有servlet容器

 

5.解读某个AutoConfiguration

DatasourceAutoConfiguration

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWnB5Q3h5,size_20,color_FFFFFF,t_70,g_se,x_16

@Configuration:当前类是一个配置类,如果配加载,和创建datasource的bean对象有关

@ConditionalOnClass({DataSource.class,EmbeddedDatabaseType.class}):当前配置类到低加载不加载取决于这个条件注解,满足条件则加载,不满足则不加载

条件:当前classpath下必须依赖DataSource这个类和EmbeddedDatabaseType.class.

@EnableConfigurationProperties:满足条件时,要加载datasource的属性,spring.datasource前缀。

**注意:当你不明白,记不住某个技术引入时调用的属性值

@Import:导入,当前配置类加载的同时,多加载2个配置类。

RedisAutoConfiguration

6.总结:

SpringBoot的自动配置原理:spingboot首先先广泛预写了大量的配置类,通过核心注解:@SpringBootApplication实现的,该注解包含了三个重要注解:

1.@SpringBootConfiguration 将类变成配置类

2.@ComponentScan 包扫描

3.@EnableAutoConfiguration 启动自动配置

sping容器会先加载应用程序中的bean,进行查缺补漏,条件性的创建需要的bean,通过注解@ConditionalOnBean或@ConditionalOnMissingBean实现过滤.

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值