容器功能
目的:
-
为了深入理解springboot的自动配置原理,需要先了解springboot的部分底层注解
-
容器功能相关的注解汇总
注解名称 功能 1 @Configuration 标注该类为配置类 2 @Bean 标注在方法上,通过方法添加组件,
常用于导入第三包中的组件3 @Compont 添加普通组件 4 @Controller 添加控制类组件 5 @Service 添加业务层组件 6 @Repository 添加持久层组件 7 @Import 快速给容器中导入组件
一、组件添加
-
创建一个配置类 - @Configuration
配合属性proxyBeanMethod使用
/* @Configuration:表明该类是配置类 ① 配置类本身也是一个组件 ② proxyBeanMethod:默认值是true,表明配置类是一个代理对象 Full配置模式:proxyBeanMethods = true,代理对象调用方法,springboot总会检查容器中是否有方法对应的组件,保持组件单实例,即外部无论获取多少次该组件,都是容器中的单实例 Lite配置模式:proxyBeanMethods = false,表明配置类不是代理对象了,即,配置类再调用方法时,就只是单纯的调用方法,不会从容器中获取,每次都创建新的对象 ③ 如果组件之间有依赖关系,proxyBeanMethods必须为true。 */ @Configuration(proxyBeanMethods = true) public class MyConfig { }
-
在配置类内以@Bean注解添加组件
@Configuration(proxyBeanMethods = true) public class MyConfig { /* @Bean:标注在方法上给容器中添加组件。默认是单实例 ① 方法名:作为组件的id, ② 返回类型:就是组件类型。 ③ 返回的值:就是组件在容器中的实例。 */ @Bean public User user01() { User zhangsan = new User("zhangsan", 18); // 与tomcatPet()组件产生了依赖 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean public Pet tomcatPet() { return new Pet("tomcat"); } }
-
Spring5中的IOC容器中添加组件的注解也可以使用
@Component、@Controller、@Service、@Repository
-
@import(Class<?> [])
写在容器中的任意一个的组件上,给容器中自动创建出引入的类的组件,引入的类可以是自建类,也可以是第三方jar包中的类。
创建的组件名默认为该类的全类名
@Import({User.class, DBNameResolver.class}) @Configuration(proxyBeanMethods = true) public class MyConfig { }
-
@Conditional()条件装配
按照条件进行装配,即满足@Conditional或其派生注解中的条件,该组件才会被装进容器
// 1.放在配置类上,如果不满足Conditional中的条件,则整个配置类中的所有组件都无法装入容器 @ConditionalOnBean(name = "user01") @Configuration(proxyBeanMethods = true) public class MyConfig { @Bean public User user01() { User zhangsan = new User("zhangsan", 18); zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean public Pet tomcatPet() { return new Pet("tomcat"); } } // 2.放在某个组件上,如果不满足Conditional中的条件,则这个组件无法装入容器 @Configuration(proxyBeanMethods = true) public class MyConfig { @Bean public User user01() { User zhangsan = new User("zhangsan", 18); zhangsan.setPet(tomcatPet()); return zhangsan; } @ConditionalOnBean(name = "user01") @Bean public Pet tomcatPet() { return new Pet("tomcat"); } }
@Conditional()的派生注解
-
@ImportResource原生配置文件导入
在配置类上,使用该注解导入第三方或者原项目中的xml配置文件中的组件
@ImportResource("classpath:beans.xml") @Configuration(proxyBeanMethods = true) public class MyConfig { }
二、配置绑定
-
配置文件:application.properties
mycar.name=BYD mycar.price=100000
-
配置绑定
方式一:@Component + @ConfigurationProperties
在bean文件夹下创建一个对应的实体类组件
/ 只有在spring容器中的组件,才能拥有SpringBoot提供的强大功能 @Component @ConfigurationProperties(prefix="mycar") public class Car { private String name; private Double price; // 此处省略了构造器、get/set方法及toString方法 }
方式二:@ConfigurationProperties +@EnableConfigurationProperties
@ConfigurationProperties(prefix="mycar") public class Car { private String name; private Double price; // 此处省略了构造器、get/set方法及toString方法 }
// 开启了Car配置绑定功能,并将Car自动注册到了容器中 @Configuration(proxyBeanMethods = true) @EnableConfigurationProperties(Car.class) public class MyConfig { }
-
业务组件
@RestController public class HelloController { @Autowired Car car; @RequestMapping("mycar") public Car handler02() { return car; } }
三、自动扫描main程序所在包下的所有组件的源码解析
-
主程序类的注解@SpringBootApplication源码
/* 主要包含三个注解 ① @SpringBootConfiguration:和@Configuration作用一样,表明主程序类也是配置类 ② @EnableAutoConfiguration:重点解析该注解源码 ③ @ComponentScan:组件扫描 */ @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} )} ) public @interface SpringBootApplication { // 省略内部程序 }
-
@EnableAutoConfiguration源码
// @AutoConfigurationPackage:重点解析 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
-
@AutoConfigurationPackage源码
// 重点解析Resistrar @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
-
Registrar,内部静态类源码
public abstract class AutoConfigurationPackages { static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { Registrar() { } // 在该方法上打断点进行De 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)); } } }
-
在registerBeanDefinitions方法上断点测试情况
四、最佳实践
-
引入相关场景启动器
在官方文档中可以查找有哪些场景启动器依赖或找某些第三方提供的场景启动器依赖
-
查看自动配置了哪些
① 手动查看,在External LIbiraries中的spring-boot-autoconfigure中
② 在配置文件中,配置debug=true,启动自动配置报告,执行主程序即可获得所有自动装配的情况,
其中生效的为Positive,未生效的为Negative
-
是否需要修改properties
-
自定义
可以自定义加入或替换组件
自定义器 xxxxCustomizer(高级特性,后续学习)
-
更改组件扫描路径
@SpringBootApplication(scanBasePackages = "com.atg")
小结
- spring主要功能之一,就是将各类的对象以组件的形式装入到IOC容器中。
- springboot中的@bean标注的方法内创建的对象就是xml配置中bean标签的