Spring @Configuration Annotation(每日一解系列)

2020-03-27 · 树下魅狐 · · 本文共2,310个字,预计阅读需要11分钟。

序言

Spring @Configuration是一个类级别的注解,用于声明一个Java类为Spring容器所管理的配置类,并再类中声明和定义一个或多个Bean方法。与此同时,@Configuration还可以与其他类级别的注解搭配使用,例如:

本节内容

1.使用@Configuration注解

与往常一样,创建一个AppConfig类,使用@Configuration进行注解,并在类内部使用@Bean注解一个bean方法。

AppConfig.java

@Configuration
public class AppConfig {

    @Bean("user")
    public UserBean userBean(){
        return new UserBean("树下魅狐");
    }

}

接下来,创建一个名为UserBean的Java类,并在main()方法中通过AnnotationConfigApplicationContext获取userBean。

UserBean.java

public class UserBean {

    private String username;

    public UserBean(String username){
        this.username = username;
        System.out.println("Initializing UserBean and  username is :"+this.username);
    }

    public String getUsername(){
        return this.username;
    }
}

ConfigurationAnnotationApplication.java

@SpringBootApplication
public class ConfigurationAnnotationApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigurationAnnotationApplication.class, args);

        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        UserBean user = (UserBean) context.getBean("user");
        System.out.println("user`s username = "+user.getUsername());
    }

}

Output

Initializing UserBean and  username is :树下魅狐
user`s username = 树下魅狐

2. @Configuration@Autowired

@Configuration注解的类中,可以使用@Autowired注解将外部化的值或者其他的Bean注入其中。例如,我们可以使用@Autowired将Spring的Environment注入到配置类中。

AppConfig.java

@Configuration
public class AppConfig {

    @Autowired
    private Environment environment;

    @Bean("user")
    public UserBean userBean(){
        System.out.println(environment.getProperty("java.home"));
        return new UserBean("树下魅狐");
    }

}

在代码中,通过environment获得java的home路径。

Output

C:\Program Files\Java\jdk1.8.0_221\jre
Initializing UserBean and  username is :树下魅狐
user`s username = 树下魅狐

3. @Configuration@PropertySource

@PropertySource注解为我们提供了一种便捷的方式将外部的配置文件属性值配置到Spring的环境中。我们可以在@Configuration注解的类上使用@PropertySource读取配置文件,并在类中使用@Value获得配置文件中属性值。首先,在类路径下创建一个名为app.properties的配置文件内容如下:

app.properties

author.email=ramostear@163.com
author.site=https://www.ramostear.com

接下来,修改AppConfig.java文件,使用@PropertySource加载application.properties文件,并在类中使用@Value读取配置项的值。

AppConfig.java

@Configuration
@PropertySource(value = "classpath:app.properties")
public class AppConfig {

    @Value("${author.email}")
    private String email;
    @Value("${author.site}")
    private String site;

    @Autowired
    private Environment environment;

    @Bean("user")
    public UserBean userBean(){
        System.out.println(environment.getProperty("java.home"));
        System.out.println("Author email:"+email);
        System.out.println("Author site:"+site);
        return new UserBean("树下魅狐");
    }

}

再次运行main()方法,观察控制台输出。

Output

C:\Program Files\Java\jdk1.8.0_221\jre
Author email:ramostear@163.com
Author site:https://www.ramostear.com
Initializing UserBean and  username is :树下魅狐
user`s username = 树下魅狐

4 @Configuration@Profile

@Profile是一个很有用的注解,它允许我们根据Spring ActiveProfile的值注册不同的配置文件。例如,在软件开发过程中,我们可以根据项目进展情况,为项目定义不同的配置,如开发用的配置,测试用的配置以及生产环境用的配置等等。在此例子中,我们通过@Profile新增两个配置类DevAppConfig.java和TestAppConfig.java,并在AppConfig.java类上加入@Profile注解。

DevAppConfig.java

@Profile("dev")
@Configuration
public class DevAppConfig {

    @Bean
    public UserBean userBean(){
        return new UserBean("谭朝红");
    }
}

TestAppConfig.java

@Profile("test")
@Configuration
public class TestAppConfig {

    @Bean
    public UserBean userBean(){
        return new UserBean("ramostear");
    }
}

AppConfig.java

@Profile("prod")
@Configuration
@PropertySource(value = "classpath:app.properties")
public class AppConfig {
    //...
}

接下来,修改main()中的代码,并启用dev的配置。

main()

public static void main(String[] args) {
        SpringApplication.run(ConfigurationAnnotationApplication.class, args);
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();    //不指定配置类

        context.getEnvironment().setActiveProfiles("dev");    //通过profile切换
        context.scan("com.ramostear.configuration.annotation");
        context.refresh();

        UserBean user = context.getBean(UserBean.class);
        System.out.println(user.getUsername());

        context.close();
    }

Output

Initializing UserBean and  username is :谭朝红
谭朝红

现在,将profile切换到test,观察控制台输出。

main()

context.getEnvironment().setActiveProfiles("test");

Output

Initializing UserBean and  username is :ramostear
ramostear

最后,将profile切回到prod。

main()

context.getEnvironment().setActiveProfiles("prod");

Output

C:\Program Files\Java\jdk1.8.0_221\jre
Author email:ramostear@163.com
Author site:https://www.ramostear.com
Initializing UserBean and  username is :树下魅狐
树下魅狐

补充

除了上述的方法外,还可以使用System.setProperty()方法设置profile。代码如下:

System.setProperty("spring.profiles.active","prod");

5. @Configuration@EnableScheduling

在Spring中,@Configuration@EnableScheduling注解搭配,可以开启Spring的定时任务功能,并使用@Scheduled注解定义定时任务。请看下面的例子:

DemoTask.java

public class DemoTask {

    private int num = 0;
    private static SimpleDateFormat sdf = 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Scheduled(fixedRate = 1000)
    public void task(){

        System.out.println(sdf.format(new Date())+": number = "+(++num));
    }
}

DemoTask.java任务比较简单,每个一秒输出当前时间和num累加的结果。接下来,在AppConfig.java中开启定时任务,并配置DemoTask bean。

AppConfig.java

@Profile("prod")
@Configuration
@PropertySource(value = "classpath:app.properties")
@EnableScheduling
public class AppConfig {
    //省略其他...

    @Bean
    public DemoTask demoTask(){
        return new DemoTask();
    }

}

Output

2020-03-27 06:12:53.048  INFO 7652 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2020-03-27 06:12:53: number = 1
2020-03-27 06:12:54: number = 2
2020-03-27 06:12:55: number = 3
2020-03-27 06:12:56: number = 4
2020-03-27 06:12:57: number = 5
2020-03-27 06:12:58: number = 6
2020-03-27 06:12:59: number = 7
2020-03-27 06:13:00: number = 8
2020-03-27 06:13:01: number = 9
2020-03-27 06:13:02: number = 10

6.@Configuration@ImportResource

Spring允许我们使用@ImportResource注解导入Spring的XML配置文件。Spring现在推荐使用Java代码的配置方式,但还是给喜好使用XML配置文件的开发者提供了通道。请看示例:

app.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean primary="true" name="unaBoot" class="com.ramostear.configuration.annotation.beans.UserBean">
        <constructor-arg name="username" value="unaBoot"/>
    </bean>
</beans>

接下来,在AppConfig.java文件中使用@ImportResource注解导入app.xml配置。

AppConfig.java

@Profile("prod")
@Configuration
@PropertySource(value = "classpath:app.properties")
@EnableScheduling
@ImportResource(value = "classpath:app.xml")
public class AppConfig {
    //省略...
}

在main()方法中获取unaBoot 并打印username的值。

main()

public static void main(String[] args) {
        SpringApplication.run(ConfigurationAnnotationApplication.class, args);
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("prod");
        context.scan("com.ramostear.configuration.annotation");
        context.refresh();
        UserBean unaBoot = (UserBean) context.getBean("unaBoot");
        System.out.println("app.xml config bean :"+ unaBoot.getUsername());
    }

Output

Initializing UserBean and  username is :unaBoot
unaBoot
app.xml config bean :unaBoot

7. @Configuration@Import

我们可以使用@Import将一个或多个被@Configuration注解的配置类导入了一个类当中。这是个不错的操作,可以将多个配置类聚合到一个类中。请看示例:

OtherAppConfig.java

@Configuration
public class OtherAppConfig {

    @Bean
    public OtherBean otherBean(){
        return new OtherBean();
    }
}

在AppConfig.java文件导入OtherAppConfig配置,main()方法中的代码保持不变,内容如下:

@Profile("prod")
@Configuration
@PropertySource(value = "classpath:app.properties")
@EnableScheduling
@ImportResource(value = "classpath:app.xml")
@Import(OtherAppConfig.class)
public class AppConfig {
    //省略其他...
}

OtherBean.java

public class OtherBean {

    public OtherBean(){
        System.out.println("Initializing other bean ....");
    }
}

Output

Initializing other bean ....

8. @Configuration@ComponentScan

@ComponentScan注解的作用是根据指定的包路径或者类,对组件进行扫描并完成自动装配工作。在前面的章节中已有介绍,在此不再赘述。

本章节通过七个详细的案例,介绍了Spring @Configuration注解的使用,如需文中完整的案例代码,你可以点击下面的地址访问github仓库进行下载。