您的位置:首页 > 编程语言 > Java开发

springboot学习之旅02-springboot自动配置原理

2020-06-04 04:40 459 查看

1.关于pom文件

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>

他的父项目是
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
他来真正管理Spring Boot应用里面的所有依赖版本;在这里插入代码片

Spring Boot的版本仲裁中心;

以后我们导入依赖默认是不需要写版本;(没有在dependencies里面管理的依赖自然需要声明版本号)



2.主程序类,主入口类

/**
*  @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {

public static void main(String[] args) {

// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}

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

他其实是一个组合注解,如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)

@SpringBootConfiguration:Spring Boot的配置类;

​ 标注在某个类上,表示这是一个Spring Boot的配置类;

​ @Configuration:配置类上来标注这个注解;

​ 配置类 ----- 配置文件;配置类也是容器中的一个组件;@Component



3.@SpringBootApplication层层剖析(自动配置原理)

1.一层层点开看
@SpringBootApplication主要要看@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这几个注解。
1.@SpringBootConfiguration–>@Configuration–>@Component
2.@EnableAutoConfiguration->@AutoConfigurationPackage & @Import–>@Import

@EnableAutoConfiguration:开启自动配置功能;

2.说明
​ 以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;

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

@AutoConfigurationPackage:自动配置包
@Import({AutoConfigurationImportSelector.class})
Spring的底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class;
将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;

3.开始讲解原理:
3.1
在AutoConfigurationImportSelector中,有selectImports这样一个方法,打断点启动的话能看到里面会自动导入项目的所有配置类。(利用AutoConfigurationImportSelector给容器中导入一些组件)

3.2.AutoConfigurationImportSelector源码解析
getCandidateConfigurations()方法
3.3
这其中的SpringFactoriesLoader.loadFactoryNames()方法我们点开进去看:

3.4
再点进去loadSpringFactories

重点来了!!!扫描所有jar包类路径下的 spring.factories
1)把扫描到的这些文件的内容包装成properties对象;
2)从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
如下图:
名字都是XXXAutoConfiguration
总结:将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;
每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;

3.5
当全部的配置类进入容器后,每一个自动配置类就会进行自动配置功能;

3.6
以HttpEncodingAutoConfiguration(Http编码自动配置)为例讲解

@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties({HttpEncodingProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和这边的HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication(
type = Type.SERVLET
)//Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效;    这边:判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//判断配置文件中是否存在某个配置  spring.http.encoding.enabled;matchIfMissing = true:如果不存在,判断也是成立的
//即使我们配置文件中不配置 spring.http.encoding.enabled=true,也是默认生效的;

public class HttpEncodingAutoConfiguration {

//他已经和SpringBoot的配置文件映射了 下面的properties就从配置文件里面获取值
private final HttpEncodingProperties properties;

//有参构造通过上方的@EnableConfigurationProperties将属性值进行绑定
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}

@Bean    //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean(CharacterEncodingFilter.class)  //容器中必须没有这个类才生效
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));
return filter;
}

根据当前不同的条件判断,决定这个配置类是否生效;
一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

3.7
所有在配置文件中能配置的属性都是在xxxxProperties类中封装者‘;配置文件能配置什么就可以参照某个功能对应的这个属性类(对应上面HttpEncodingAutoConfiguration 的例子)

@ConfigurationProperties(
prefix = "spring.http.encoding"
)
public class HttpEncodingProperties {

3.8
所以根据上方例子,我们就可以根据配置文件的前缀名,自己在application.yml中重新给这些默认属性值赋值

精髓:

1)、SpringBoot启动会加载大量的自动配置类

2)、我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;

3)、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)

4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值;

再者:
xxxxAutoConfigurartion:自动配置类;

给容器中添加组件

xxxxProperties:封装配置文件中相关属性;

3.9
关于上方的@ConditionalOnClass

@Configuration
@EnableConfigurationProperties({HttpEncodingProperties.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {

我们点开进去看一下,用的实际上还是spring底层@Conditional

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
Class<?>[] value() default {};

String[] name() default {};
}

再点@OnClassCondition进去看一下
这边有一个match方法,用于判断是否满足条件;

必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;

@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

自动配置类必须在一定的条件下才能生效;

我们怎么知道哪些自动配置类生效;

我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

=========================
AUTO-CONFIGURATION REPORT
=========================

Positive matches:(自动配置类启用的)
-----------------

DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)

Negative matches:(没有启动,没有匹配成功的自动配置类)
-----------------

ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)

AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)

看日志里面的did not match 说明没有用到

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: