背景
SpringBoot 依赖注解来简化了参数配置,通过使用默认值实现了工程可以开箱即用。
本文来从注解的角度,学习一下 SpringBoot。
罗列的内容较大,使用时只需要有个大概印象即可。
SpringBoot 中基本注解
新建一个空应用时,遇到的注解有:
- 1 SpringBootApplication
- 1.1 SpringBootConfiguration
- 1.1.1 Configuration
- 1.1.1.1 Component
- 1.2 EnableAutoConfiguration
- 1.2.1 AutoConfigurationPackage
- 1.2.2 Import
- 1.3 ComponentScan
- 1.4 AliasFor
- 2 RunWith: 测试相关
- 3 SpringBootTest: 测试相关
- 3.1 BootstrapWith
SpringBootApplication
SpringBootApplication 是一个组合注解,包含下列 3 个注解:
- SpringBootConfiguration
- EnableAutoConfiguration
- ComponentScan
同时声明了 4 个接口
- exclude(): 排除 auto-configuration 类
- excludeName(): 排除 auto-configuration 类名
- scanBasePackages(): 自动扫描注解类的基类
- scanBasePackageClasses(): 自动扫描注解类的类列表
用来灵活的配置不进行 auto-configuration 的类,和扫描注解的类。
SpringBootConfiguration
表明 SpringBoot 的配置可以从 Configuration 中自动得到。
被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境
应用应该只包含一个 SpringBootConfiguration,基本所有的 SpringBoot 应用都会继承这个类。
Configuration
Configuration 表明类中定义了一些 Bean 方法,可以通过 Spring 来管理生成 Bean 的定义和运行时的请求。
@Configuration public class AppConfig { @Bean public MyBean myBean() { // instantiate, configure and return bean ... } }
Bean 的发现
Spring 怎么发现 Bean 呢?
AnnotationConfigApplicationContext
第一种方法是通过 AnnotationConfigApplicationContext,示例如下:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class); ctx.refresh(); MyBean myBean = ctx.getBean(MyBean.class); // use myBean ...
spring beans xml
第二种方式是通过 spring 的 <beans>
xml,如下:
<beans> <context:annotation-config/> <bean class="com.acme.AppConfig"/> </beans>
SomeBean
第三种方式是通过组件扫描,如下:
@Configuration public class AppConfig { private final SomeBean someBean; public AppConfig(SomeBean someBean) { this.someBean = someBean; } // @Bean definition using "SomeBean" }
也可以通过 ComponentScan 注解来扫描
@Configuration @ComponentScan("com.acme.app.services") public class AppConfig { // various @Bean definitions ... }
Bean 的调用
怎么样在外面使用呢?
通过 Environment API
方法一:通过 Environment
API,如下:
@Configuration public class AppConfig { @Autowired Environment env; @Bean public MyBean myBean() { MyBean myBean = new MyBean(); myBean.setName(env.getProperty("bean.name")); return myBean; } }
也可以同时通过 PropertySource
来指定 Configuration
中的配置,示例如下:
@Configuration @PropertySource("classpath:/com/acme/app.properties") public class AppConfig { @Inject Environment env; @Bean public MyBean myBean() { return new MyBean(env.getProperty("bean.name")); } }
通过 Value 注释
方法二:通过 @Value
注解,示例如下:
@Configuration @PropertySource("classpath:/com/acme/app.properties") public class AppConfig { @Value("${bean.name}") String beanName; @Bean public MyBean myBean() { return new MyBean(beanName); } }
在启用了 Spring 的 PropertySourcesPlaceholderConfigurer 后,这样使用就很方便了。
编写 Configuration 类
怎么样编写一个 Configuration 类呢?
import 注解
方法一:通过 import 注解
@Configuration public class DatabaseConfig { @Bean public DataSource dataSource() { // instantiate, configure and return DataSource } } @Configuration @Import(DatabaseConfig.class) public class AppConfig { private final DatabaseConfig dataConfig; public AppConfig(DatabaseConfig dataConfig) { this.dataConfig = dataConfig; } @Bean public MyBean myBean() { // reference the dataSource() bean method return new MyBean(dataConfig.dataSource()); } }
这样,通过注册 AppConfig
,可以同时使用 AppConfig
和引入的 DatabaseConfig
。
new AnnotationConfigApplicationContext(AppConfig.class);
通过 Profile 注解
方法二,通过 @Profile
注解
通过 @Profile
来表明只有 profile(s)活跃时,才来处理。
@Profile("development") @Configuration public class EmbeddedDatabaseConfig { @Bean public DataSource dataSource() { // instantiate, configure and return embedded DataSource } } @Profile("production") @Configuration public class ProductionDatabaseConfig { @Bean public DataSource dataSource() { // instantiate, configure and return production DataSource } }
也可以通过 @Bean
注释,来实现 profile 的条件执行。
@Configuration public class ProfileDatabaseConfig { @Bean("dataSource") @Profile("development") public DataSource embeddedDatabase() { ... } @Bean("dataSource") @Profile("production") public DataSource productionDatabase() { ... } }
通过 Spring xml 和 ImportResource 注解
方法三,通过 Spring xml 和 ImportResource
注解,如:
@Configuration @ImportResource("classpath:/com/acme/database-config.xml") public class AppConfig { @Inject DataSource dataSource; // from XML @Bean public MyBean myBean() { // inject the XML-defined dataSource bean return new MyBean(this.dataSource); } }
通过嵌套的 Configuration 类
方法四,通过嵌套的 Configuration
类,如下:
@Configuration public class AppConfig { @Inject DataSource dataSource; @Bean public MyBean myBean() { return new MyBean(dataSource); } @Configuration static class DatabaseConfig { @Bean DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); } } }
嵌套的情况,只需要注册 AppConfig
即可。
lazy 启动
默认情况下,@Bean
方法会在容器启动时初始化。如果不想这样做的话,可以通过增加 @Lazy
注解,来实现 lazy 初始化。
在测试中使用
示例
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes={AppConfig.class, DatabaseConfig.class}) public class MyTests { @Autowired MyBean myBean; @Autowired DataSource dataSource; @Test public void test() { // assertions against myBean ... } }
启用内置 Spring 特征
通过 @Enable
注解来启动 Spring 特征,比如:
@EnableAsync
@EnableScheduling
@EnableTransactionManagement
@EnableAspectJAutoProxy
@EnableWebMvc
Component
表明这个类,在从包路径搜索类的注解时,可以被搜索到。
EnableAutoConfiguration
允许 SpringBoot 根据应用中声明的依赖,对 Spring 框架上下文的进行自动配置。
使用 SpringBootApplication 时,会自动启用 EnableAutoConfiguration。不过在类中多写一个 EnableAutoConfiguration 也不会有副作用。
其中提供了 exclude()
和 excludeName()
方法,
AutoConfigurationPackage
表明本注解类会使用 AutoConfigurationPackages 进行注册。
Import
表明需要引入的 Configuration 配置类
ComponentScan
表明 Configuration 类中使用中组件扫描指令。
组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Booter.class所在的包路径下文件,所以最好将该启动类放到根包路径下
详情略
AliasFor
AliasFor 设置注解的别名。
使用场景
字段别名
示例如下,@ContextConfiguration
中,locations 和 value 互为别名。
public @interface ContextConfiguration { @AliasFor("locations") String[] value() default {}; @AliasFor("value") String[] locations() default {}; // ... }
字段属性别名
示例如下,
@ContextConfiguration public @interface XmlTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xmlFiles(); }
在 @XmlTestConfig
中,xmlFiles
是 @ContextConfiguration
中 locations
的别名,即 xmlFiles 参数覆盖了 @ContextConfiguration
中的 locations
属性。
字段属性字段别名
就是上面两种情况的综合体
@ContextConfiguration public @interface MyTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] value() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] groovyScripts() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xmlFiles() default {}; }
其中 value()
,groovyScripts()
和 xmlFiles()
互为别名,同是也都是 ContextConfiguration
中 locations
的别名。
注解中隐式别名
@MyTestConfig public @interface GroovyOrXmlTestConfig { @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts") String[] groovy() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xml() default {}; }
在 @GroovyOrXmlTestConfig
中,groovy
覆盖了 @MyTestConfig
中的 groovyScripts
属性,xml
覆盖了 @ContextConfiguration
中的 locations
属性,其中 groovy
和 xml
又互为别名,均覆盖了 @ContextConfiguration
中的 locations
属性。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于