我们知道jar包方式运行需要main方法,SpringBoot已为我们自动生成,这个类便是项目启动入口。
@SpringBootApplication
public class BlogDemoApplication {
public static void main(String[] args) {
SpringApplication.run(BlogDemoApplication.class, args);
}
}
@SpringBootApplication
- 入口类上的注解@SpringBootApplication是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) })
public @interface SpringBootApplication {
...
}
- 说明它是@ComponentScan、@SpringBootConfiguration和@EnableAutoConfiguration三个注解的组合。
@ComponentScan
- @ComponentScan是Spring框架原有的注解,在spring-context组件下,用来开启自动扫描Bean并解析注解注入。
- 可以用basePackages指定扫描的包,缺省情况下默认扫描被注解类所在的包。SpringBoot项目中一般会将入口类放在顶层目录,这样默认就会扫描整个项目。
@SpringBootConfiguration
- @SpringBootConfiguration是SpringBoot新增的注解,在spring-boot组件下,定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
- 相当于注解@Configuration,配备了该注解的类就能够以JavaConfig的方式完成一些配置,可以不再使用XML配置。所以在入口类内也可以以JavaConfig的方式定义Bean。
@EnableAutoConfiguration
- @EnableAutoConfiguration是SpringBoot新增的注解,在spring-boot-autoconfigurate组件下,它是SpringBoot开启自动配置的关键,是开启自动配置的入口。其定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
- 以上简单解析了SpringBoot的入口类,一个由SpringBoot自动生成的java类,虽然只有短短几行代码,却引发了Spring上下文的创建的一系列事件。首先SpringBoot将入口类传入作为资源的起点,当解析到入口类的时候发现其上的注解又开启了自动配置和包扫描,这样我们自定义的Bean就会被加载进去完成创建和依赖。
难道所有的配置类都会被加载吗
- 那么来看看是如何实现的,以Redis的配置类RedisAutoConfiguration为例,看下类源码:
@Configuration
// 当存在RedisOperations时,才会加载该配置类
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
// 当不存在名为"redisTemplate"的bean时,才会创建该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
// 当Spring上下文中不存在StringRedisTemplate类实例的时候,才会创建该bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
- 这里利用了Spring条件注解的特性,通过设定一定的条件来实现不同场景下加载不同的配置。
- 自动配置类生效的条件通常是我们引入了相关的组件,如果没有引入组件,那么就算包含在spring.factories文件中也不会被加载。而是否要注入Bean则要看当前上下文中是否已经存在相应的Bean。如果不存在,那么由默认配置来补充。如果已经存在了,自动配置会不满足注解条件,就不会被创建。
- 有了这两点,可以做到当我们不做任何配置的时候可以用默认配置来运用新组件,而当我们需要对配置进行调整的时候用自定义的配置来覆盖即可。
- SpringBoot在Spring原有的基础上,通过拼凑组合又实现了一个强大的特性——自动配置。
自动配置让我们可以在不做任何配置的情况下直接使用一个新的类库(前提是足够普遍),也能满足我们自定义配置的需求
网友评论