侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

SpringBoot自动配置原理

coydone
2022-04-02 / 0 评论 / 0 点赞 / 317 阅读 / 7,484 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

SpringBoot特点

依赖管理

  • 父项目做依赖管理
依赖管理    
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
    <relativePath/>
</parent>

他的父项目
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.5.6</version>
</parent>
它来真正管理SpringBoot应用里面的所有依赖版本,
几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制。
  • 开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter:第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.5.6</version>
  <scope>compile</scope>
</dependency>
  • 无需关注版本号,自动版本仲裁。引入依赖默认都可以不写版本。引入非版本仲裁的jar,要写版本号。

  • 可以修改默认版本号

1、查看spring-boot-dependencies里面规定当前依赖的版本用的key。
2、在当前项目里面重写配置
<properties>
    <mysql.version>5.1.43</mysql.version>
</properties>

自动配置

  • 自动配好Tomcat:SpringBoot会自动引入Tomcat依赖,并配置Tomcat。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.5.6</version>
    <scope>compile</scope>
</dependency>
  • 自动配好SpringMVC:SpringBoot引入SpringMVC全套组件,自动配好SpringMVC常用组件(功能)。

  • 自动配好Web常见功能,如:字符编码问题。SpringBoot帮我们配置好了所有Web开发的常见场景。

  • 默认的包结构:

    • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来。

    • 无需以前的包扫描配置。

更改扫描路径
@SpringBootApplication(scanBasePackages="com.coydone")
或者使用 @ComponentScan 指定扫描路径

@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.coydone")
  • 各种配置拥有默认值。

    • 默认配置最终都是映射到某个类上,如:MultipartProperties。

    • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象。

  • 按需加载所有自动配置项

    • 非常多的starter。

    • 引入了哪些场景这个场景的自动配置才会开启。

    • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面。

容器功能

组件添加

@Configuration

Full模式与Lite模式

/**
 * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
 * 2、配置类本身也是组件
 * 3、proxyBeanMethods:代理bean的方法
,默认为true
 * Full(proxyBeanMethods = true) 保证每个@Bean方法被调用多少次返回的组件都是单实例的
 * Lite(proxyBeanMethods = false)每个@Bean方法被调用多少次返回的组件都是新创建的
 * 组件依赖必须使用Full模式默认。其他默认为否Lite模式
 *
 * 如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
 * SpringBoot总会检查这个组件是否在容器中有。
 */
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类=配置文件
public class MyConfig {
    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
     * @return
     */
    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user组件依赖了Pet组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }
    @Bean("tom")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}

最佳实战

  • 配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。

  • 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式。

@Bean、@Component、@Controller、@Service、@Repository

都是向Spring容器中注入组件。

@ComponentScan、@Import

//@Import({User.class, DBHelper.class})
//给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
public class MyConfig {
}

@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入。

原生配置文件引入

@ImportResource

//beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="haha" class="com.coydone.pojo.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="hehe" class="com.coydone.pojo.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {}

配置绑定

使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用。

@ConfigurationProperties

/**
 * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
 */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
	//省略getter、setter、toString、构造方法
}

@EnableConfigurationProperties + @ConfigurationProperties:相当于xml文件+bean配置。

@Component + @ConfigurationProperties

@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}

自动配置原理简述

引导加载自动配置类

//@SpringBootApplication
//SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类
//SpringBoot就应该运行这个类的main方法来启动SpringBoot应用

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}

1、@SpringBootConfiguration

@SpringBootConfiguration注解类中有@Configuration,代表当前是一个配置类。

2、@ComponentScan

指定扫描哪些Spring注解。

3、@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

(1)@AutoConfigurationPackage:自动配置包,指定了默认的包规则。

@Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来,MainApplication(主启动类)所在包下

(2)@Import(AutoConfigurationImportSelector.class)

  1. 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件。

  2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类。

  3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件。

  4. META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件。spring-boot-autoconfigure-2.5.6.jar包里面也有META-INF/spring.factories

按需开启自动配置项

虽然我们100多个场景的所有自动配置启动的时候默认全部加载。XxxxAutoConfiguration按照条件装配规则(@Conditional),最终会按需配置。

@Bean
@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
//容器中没有这个名字 multipartResolver 的组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) 
public MultipartResolver multipartResolver(MultipartResolver resolver) {
    //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
    //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
    // Detect if the user has created a MultipartResolver but named it incorrectly
    return resolver;
}
//给容器中加入了文件上传解析器

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先。

@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
}

总结

  • SpringBoot先加载所有的自动配置类(XxxAutoConfiguration)。

  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。XxxxProperties里面拿。XxxProperties和配置文件进行了绑定。

  • 生效的配置类就会给容器中装配很多组件。

  • 只要容器中有这些组件,相当于这些功能就有了。

  • 定制化配置

    • 用户直接自己@Bean替换底层的组件。

    • 用户去看这个组件是获取的配置文件什么值就去修改。

XxxAutoConfiguration给我们导入许多组件→组件从XxxProperties里面拿值→ application.properties。

最佳实践

引入场景依赖:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter。

查看自动配置了哪些(选做)

  • 自己分析,引入场景对应的自动配置一般都生效了。

  • 配置文件中 debug=true 开启自动配置报告。Negative(不生效)/Positive(生效)。

是否需要修改

自定义加入或者替换组件:1、@Bean、@Component等。2、自定义器XxxCustomizer等。

SpringApplication.run()

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行。

SpringApplication类,这个类主要做了以下四件事情:

  1. 推断应用的类型是普通的项目还是Web项目,

  2. 查找并加载所有可用初始化器,设 置到initializers属性中,

  3. 找出所有的应用程序监听器,设置到listeners属性中,

  4. 推断并设置main()方法的定义类,找到运行的主类。

run()方法流程

0

评论区