SpringBoot 原理
1 配置文件
1.1 配置文件优先级
1.1.1 数据冲突优先级
properties>yml>yaml
1.2 临时改变参数数据
1.2.1 java系统属性参数
-D属性名=属性值
1.2.2 命令行属性参数
--属性名=属性值
1.3 整个优先级
命令行参数>java系统属性>properties>yml>yaml
2 bean的原理
2.1 bean的主动获取
2.1.1 根据名称获取
Object getBean (String name)
2.1.2 根据类型获取
<T> T getBean(Class<T> requiredType)
2.1.3 根据名称和类型获取
<T> T getBean(String name, Class<T> requiredType)
//引入applicantionContext 为spring容器
@Autowired
private ApplicationContext applicationContext;
//获取bean对象
@Test
public void testGetBean(){
//根据bean的名称获取
Object deptController = applicationContext.getBean("dvc");
System.out.println(deptController);
//根据bean的类型获取
DeptController bean = applicationContext.getBean(DeptController.class);
System.out.println(bean);
//根据bean的名称 及 类型获取
DeptController deptController1 = applicationContext.getBean("dvc", DeptController.class);
System.out.println(deptController1);
}
2.1.4
不进行属性依赖注入,也不进行@Bean方法参数注入,如果需要使用对象可以直接通过获取容器再获取对象方式得到对象
2.1.5 spring容器
BeanFactory 顶层父容父类(spring框架3.0版本之前使用)
AppcationContext子接口 (spring框架3.0版本之后使用)功能更加强大
2.2 bean的作用域
加注与要注入spring ioc容器中的类上
@Scope("prototype")
@RestController (value = "dvc")
@RequestMapping("/depts")
public class DeptController {
省略....
}
}
2.2.1 singleton (单例)
容器内同名称的bean只有一个实例, 加入到spring容器中, 被共享, 容器销毁这个单例对象才会销毁.
单例在spring容器创建的时候就已经创建了, 如果需要延迟加载需添加@lazy
运行以下代码, 输出十个相同的类
@Test
public void testScope(){
for (int i = 0; i < 10; i++) {
Object dvc = applicationContext.getBean("deptControlle");
System.out.println(dvc);
}
}
结果:
com.example.controller.DeptController@2c16677c
com.example.controller.DeptController@2c16677c
......
com.example.controller.DeptController@2c16677c
2.2.2 prototype (非单例)
每次使用该bean时会创建新的实例, 多例会被jvm的垃圾回收器回收
注意prototype本身就是懒加载, 只有被调用的时候才加载
运行上面代码输出十个不同的类
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
ִDeptController已经被创建了....
com.example.controller.DeptController@790654d5
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
ִDeptController已经被创建了....
com.example.controller.DeptController@5f935d49
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
......
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
ִDeptController已经被创建了....
com.example.controller.DeptController@316d30ad
2.2.3 单例对象创建的时机
项目启动的时候运行引导类,里面扫描spring注解有,有注解立刻创建对象加入spring容器,所以服务器启动时就创建对象
2.2.4 @Lazy (延迟创建)
只有在单例创建对象模式有效。服务器启动时不创建对象,而是在第一次获取的时候spring容器才创建对象加入容器里面。不推荐使用
2.2.5 @Scope
无参数设置就是单例创建
2.2.6 @Scope("prototype")
设置当前对象多例创建, 每次从spring容器里面获取出来的时候都会创建新的对象
2.3 加载第三方bean
2.3.1 为什么需要@Bean
因为项目中自定义的bean对象, 才可以使用@Component及其衍生注解, 但是部分第三方的bean对象在项目中也运用广泛, 就需要@Bean将第三方bean对象交给spring管理
2.3.2 @Bean
/\ @Bean 用于在方法上,可以将返回的返回值对象加入spring容器中,并且方法名作为对象的别名
/\ @Bean("abc") //@Bean也可以自定义别名
/\ 如果@Bean定义方法需要使用其他容器对象,可以通过形参注入使用
2.3.3 如何添加第三方Bean
例如, 要添加一个第三方工具类Utils下的一个HeaderParser类
public class HeaderParser {
public void parse(){
System.out.println("HeaderParser ... parse ...");
}
}
1). 创建一个配置类, 添加注解@Configuration 添加构造的方法并@Bean, 注意此时的方法名就是Bean的名字
@Configuration
public class Configs {
@Bean
public HeaderParser headerParser(){
return new HeaderParser();
}
}
2) 创建一个ImportSelect类, 并重写ImportSelect方法
public class ImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.Configs"};
}
}
3) 添加一个EnableHeaderConfig的注解并注入ImportSeclect
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(ImportSelector.class)
public @interface EnableHeaderConfig {
}
4) 在启动类上注入 (本义就是一个扫描器, 查找需要注入的bean), 可以直接注入其他class文件, 但是规范操作是注入importselector
// @ComponentScan({"com.example","com.example"})
// @Import({HeaderParser.class,HeaderGenerator.class})
// @Import(Configs.class)
@Import(ImportSelector.class)
// @EnableHeaderConfig
@SpringBootApplication
public class Day29SpringbootConfigTheoryApplication {
public static void main(String[] args) {
SpringApplication.run(Day29SpringbootConfigTheoryApplication.class, args);
}
}
5) 然后就可以调用了
public void testItheimaUtils(){
HeaderParser b = (HeaderParser)applicationContext.getBean("headerParser");
System.out.println(b);
}
2.4 自动配置的底层原理
运行类上的@SpringBootApplication
@SpringBootConfiguration: 用于标识该类是一个基于 Spring Boot 的配置类。它会替代传统的 @Configuration 注解,表示这个类被用作配置文件。
@EnableAutoConfiguration: 自动配置的核心, 用于自动配置 Spring Boot 应用程序。它会根据 classpath 中的依赖以及其他配置信息,尽可能地推断并自动配置 Spring Bean。通过这个注解,可以减少很多繁琐的手动配置。
@ComponentScan: 这个注解用于指定要扫描的组件的包路径。它会自动扫描并注册具有 @Component 及其衍生注解(如 @Service、@Repository 等)的类,将它们转换为 Spring Bean。
@Import(AutoConfigurationImportSelector.class) 注解的作用是将 AutoConfigurationImportSelector 类作为一个配置类导入到当前配置类中,从而启用 Spring Boot 的自动配置机制。
通过导入AutoConfigurationImportSelector,Spring Boot 可以根据您的项目依赖和配置信息,自动导入相应的自动配置类,将其加入到应用的 Spring 上下文中。这些自动配置类会根据约定和规则为应用自动配置一些默认行为,例如设置数据源、配置日志、创建默认的 Bean 等。
getCandidateConfigurations(annotationMetadata, attributes) 方法用于根据注解元数据和属性信息获取候选的自动配置类列表, 筛选出符合条件的自动配置类,并最终由 Spring 容器加载和处理
底层就是在如图所示的两个路径中寻找是否有自动配置类, 有则添加, 没有则不添加
3 Springboot原理
3.1 起步依赖
3.1.1 定义
由于Maven的依赖传递, 首先官方提供的启动器里面提供了很多相关的依赖, 其次模块或项目会依赖springboot父项目, 提供了很多依赖的版本锁定,所有springboot项目就可以统一使用父项目的依赖版本,解决了版本的冲突
3.2 自动配置
3.2.1 定义
springboot项目除了自己使用注解将对象放入IOC容器,还有一部分对象是通过springboot自动配置将其资源加入到IOC容器中
3.2.2 自动配置方案一
@ComponentScan({"com.example","com.itheima"}) 扫描指定包, 并在spring自动配置过程中扫描自己的项目的包(启动类所在的包及其子包)
3.2.3 自动配置方案二
使用@Import导入, 导入的类会被Spring加载到IOC容器中.
实现步骤:
第三方资源:
1) 创建类实现ImportSelector接口重写selectImports方法
2) 创建自定义注解使用@Import设置上面的实现类
3) 当前项目使用第三方资源加入IOC容器,在启动类上使用上面注解
3.3 自动配置原理分析
3.4 @Conditional
3.4.1 @ConditioanlOnClass
当前环境存在指定这个类时, 才声明该Bean
3.4.2 @ConditionalOnMissingBean
当不存在当前类型的bean时, 才声明该bean
3.4.3 @ConditionalOnProperty(name= "name", havingValue="itheima")
当配置文件中存在对应的属性和值, 才注册bean到IOC容器