背景
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
属性。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于