1. SpringBoot 启动主程序类:
- @SpringBootApplication
- public class DemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(DemoApplication.class, args);
- }
- }
每次我们直接直接启动这个启动类, SpringBoot 就启动成功了, 并且帮我们配置了好多自动配置类.
其中最重要是 @SpringBootApplication 这个注解, 我们点进去看一下.
2. SpringBootApplication 注解:
- @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 {
三个比较重要的注解:
@SpringBootConfiguration : Spring Boot 的配置类, 标注在某个类上, 表示这是一个 Spring Boot 的配置类
@EnableAutoConfiguration: 开启自动配置类, SpringBoot 的精华所在.
@ComponentScan 包扫描
以前我们需要配置的东西, Spring Boot 帮我们自动配置;@EnableAutoConfiguration 告诉 SpringBoot 开启自动配置功能; 这样自动配置才能生效;
3. EnableAutoConfiguration 注解:
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
- public @interface EnableAutoConfiguration {
两个比较重要的注解:
@AutoConfigurationPackage: 自动配置包
@Import: 导入自动配置的组件
4. AutoConfigurationPackage 注解:
- static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
- @Override
- public void registerBeanDefinitions(AnnotationMetadata metadata,
- BeanDefinitionRegistry registry) {
- register(registry, new PackageImport(metadata).getPackageName());
- }
它其实是注册了一个 Bean 的定义.
new PackageImport(metadata).getPackageName(), 它其实返回了当前主程序类的 同级以及子级 的包组件.
以上图为例, DemoApplication 是和 demo 包同级, 但是 demo2 这个类是 DemoApplication 的父级, 和 example 包同级
也就是说, DemoApplication 启动加载的 Bean 中, 并不会加载 demo2, 这也就是为什么, 我们要把 DemoApplication 放在项目的最高级中.
5. Import(AutoConfigurationImportSelector.class) 注解:
可以从图中看出 AutoConfigurationImportSelector 继承了 DeferredImportSelector 继承了 ImportSelector
ImportSelector 有一个方法为: selectImports.
- @Override
- public String[] selectImports(AnnotationMetadata annotationMetadata) {
- if (!isEnabled(annotationMetadata)) {
- return NO_IMPORTS;
- }
- AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
- .loadMetadata(this.beanClassLoader);
- AnnotationAttributes attributes = getAttributes(annotationMetadata);
- List<String> configurations = getCandidateConfigurations(annotationMetadata,
- attributes);
- configurations = removeDuplicates(configurations);
- Set<String> exclusions = getExclusions(annotationMetadata, attributes);
- checkExcludedClasses(configurations, exclusions);
- configurations.removeAll(exclusions);
- configurations = filter(configurations, autoConfigurationMetadata);
- fireAutoConfigurationImportEvents(configurations, exclusions);
- return StringUtils.toStringArray(configurations);
- }
可以看到第九行, 它其实是去加载 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 外部文件. 这个外部文件, 有很多自动配置的类. 如下:
6. 如何自定义自己的 Bean:
我们以 RedisTemplate 为例:
- @Configuration
- @ConditionalOnClass(RedisOperations.class)
- @EnableConfigurationProperties(RedisProperties.class)
- @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
- public class RedisAutoConfiguration {
- @Bean
- @ConditionalOnMissingBean(name = "redisTemplate")
- public RedisTemplate<Object, Object> redisTemplate(
- RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
- RedisTemplate<Object, Object> template = new RedisTemplate<>();
- template.setConnectionFactory(redisConnectionFactory);
- return template;
- }
- @Bean
- @ConditionalOnMissingBean
- public StringRedisTemplate stringRedisTemplate(
- RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
- StringRedisTemplate template = new StringRedisTemplate();
- template.setConnectionFactory(redisConnectionFactory);
- return template;
- }
- }
我们每次在 Spring 中使用 Redis, 都会使用到 RedisTemplate 这个工具类, 但是他默认给我们返回的这个工具类, 可能不是很符合我们的要求. 比如: 我们想要开启事务, 或者想要改变它默认的序列化.
这时候该如何去做呢?
根据前面的分析, 只要我们在容器中放入一个 RedisTemplate Bean 即可.
- @Bean("redisTemplate")
- public RedisTemplate<Object, Object> myRedisTemplate(
- RedisConnectionFactory redisConnectionFactory) {
- RedisTemplate<Object, Object> template = new RedisTemplate<>();
- template.setConnectionFactory(redisConnectionFactory);
- // 修改序列化为 Jackson
- template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
- // 开启事务
- template.setEnableTransactionSupport(true);
- return template;
- }
我们自己定义我们的 RedisTemplate 模板, 修改序列化, 开启事务等操作.
我们将我们自己的 Bean 加入到 IoC 容器中以后, 他就会默认的覆盖掉原来的 RedisTemplate, 达到定制的效果.
我们在以 Kafka 为例:
假设我们想要消费的对象不是字符串, 而是一个对象呢? 比如 Person 对象, 或者其他 Object 类呢?
1: 我们首先去查找 KafkaAutoConfiguration(xxxAutoConfiguration), 看看是否有关于 Serializer 属性的配置
2: 假设没有我们就去 KafkaProperties 文件查找是否有 Serializer 的配置
然后直接在 application.properties 修改默认序列化就好, 连 Bean 都不需要自己重写.
类似这种, 可以使用 Spring 提供的 JSON 序列化, 也可以自动使用第三方框架提供的序列化, 比如 Avro, Protobuff 等
- spring.kafka.producer.key-serializer=org.springframework.kafka.support.serializer.JsonSerializer
- spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
- spring.kafka.consumer.key-deserializer=com.example.common.MyJson
- spring.kafka.consumer.value-deserializer=com.example.common.MyJson
后记:
很多时候我们刚开始看一个知识点, 不懂迷茫的时候, 真的不要慌, 可能说明你暂时的知识储备还不够理解.
等你经过不断的学习, 不断的深入以后
突然有一天, 你会突然的醒悟
哇! 原来他讲的是这个意思
可能我们不理解, 我们可以去尝试去看两遍, 三遍, 甚至更多遍, 突然会有一个时刻, 你会醒悟过来的
且行且珍惜, 共勉
来源: https://www.cnblogs.com/wenbochang/p/9851314.html