SpringBoot 中的注解学习

本贴最后更新于 2103 天前,其中的信息可能已经天翻地覆

背景

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@ContextConfigurationlocations 的别名,即 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() 互为别名,同是也都是 ContextConfigurationlocations 的别名。

注解中隐式别名

@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 属性,其中 groovyxml 又互为别名,均覆盖了 @ContextConfiguration 中的 locations 属性。

参考

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3167 引用 • 8207 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...