了解自动配置原理
了解自动配置原理
SpringBoot特点
依赖管理
父项目做依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
它的父项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
在这个父项目中properties
定义了很多jar包版本号,因此我们在引入相关依赖时,不用指定版本号
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
如果不想用父依赖的相关版本号,可以pom定义properties然后写相关版本。或者直接在这里写版本
</dependency>
开发导入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-web</artifactId>
</dependency>
自动配置
在spring-boot-starter-web
里面引入了很多依赖
自动配好tomcat
引入tomcat依赖,配置tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
自动配好springMVC
引入SpringMVC全套组件,自动配好SpringMVC常用组件(功能)
自动配置好Web常见功能,如:字符编码问题
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//ioc容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class);
//查看容器里面的组件
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for(String name:beanDefinitionNames){
System.out.println(name);
}
}
}
输出
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来无需以前的包扫描配置
想要改变扫描路径,@SpringBootApplication(scanBasePackages="com.kkrot")
或者@ComponentScan 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.kkrot.boot")
各种配置拥有默认值
默认配置最终都是映射到某个类上,如:MultipartProperties
配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter 引入了哪些场景这个场景的自动配置才会开启 SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
容器功能
组件添加
@Configuration
/**
* 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2、配置类本身也是组件
* 3、proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
* Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
* 组件依赖(user里面有pet属性)必须使用Full模式默认。其他默认是否Lite模式
*/
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean
public User getUser(){
User user = new User();
//user组件依赖了Pet组件
user.setPet(getPet());
return user;
}
@Bean("tom")
public Pet getPet(){
Pet pet = new Pet();
pet.setName("kk");
return pet;
}
}
//主启动类
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//ioc容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class);
//配置类也可以获取
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
//SpringBoot总会检查这个组件是否在容器中有。
//保持组件单实例
User user = bean.getUser();
User user1 = bean.getUser();
System.out.println(user == user1);
//组件依赖,则proxyBeanMethods = true
User user01 = run.getBean("getUser", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));
}
}
@Bean、@Component、@Controller、@Service、@Repository
@ComponentScan、@Import
ComponentScan:根据定义的扫描路径,把符合扫描规则的类装配到spring容器中
Import:
- @Import通过快速导入的方式实现把实例加入spring的IOC容器中
- @Import注解的作用和在使用spring的xml配置时用到的类似。但应注意是@Import在使用时,
- 必须要保证能被IOC容器扫描到,所以通常它会和@Configuration或者@ComponentScan配套使用。
- @Import在使用时可以声明在JAVA类上,或者作为元注解使用(即声明在其他注解上)
@Import({User.class, DBHelper.class})
@Configuration()
public class MyConfig {
}
@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
@ConditionalOnBean(name = "tom")//当容器中,有tom 下面这些注册才会生效 也可以加在方法上
public class MyConfig {
原生配置文件引入
@ImportResource
引入原生xml配置文件中的相关配置
@ImportResource("classpath:bean.xml")
public class MyConfig {
User user = run.getBean("userXml",User.class);
System.out.println(user);
配置绑定
@ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
........
}
mycar.name=BB
mycar.price=10000
@RestController
public class HelloController {
@Autowired
private Car car;
@RequestMapping("/car")
public String car(){
return car.toString();
}
}
@ConfigurationProperties
@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}
自动配置原理入门
引导加载自动配置类
@SpringBootApplication 下有三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
@SpringBootConfiguration
@Configuration。代表当前是一个配置类
@ComponentScan
指定扫描哪些。
EnableAutoConfiguration
这个注解下也有两个注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage
自动配置包?指定了默认的包规则
@Import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
//所以也就是为什么 默认扫描的包在主启动类包下
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
@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.3.4.RELEASE.jar包里面也有META-INF/spring.factories
按需开启自动配置项
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional
),最终会按需配置。
修改默认配置
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先。
例如:如果我们想替换底层的字符集的配置,则在我们自己的配置类里面,加如下代码即可。
@Bean
@ConditionalOnMissingBean//如果容器中有该bean 则不被注册 以用户配置的优先
public CharacterEncodingFilter characterEncodingFilter() {
}
总结:
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
生效的配置类就会给容器中装配很多组件
只要容器中有这些组件,相当于这些功能就有了
定制化配置
- 用户直接自己@Bean替换底层的组件
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties