@Configuration
注解变为Spring的配置类,然后添加组件扫描@ComponentScan
,Spring在启动的时候就会读入这个配置类,然后就可以从容器里获得Bean了。
通过配置类自动扫描配置Bean
将上边所有写好了注解的Bean复制到一个新包里,这次不用新建XML文件了,而是在新包里创建一个Java类,名字可以任意,但为了方便,可以叫SpringConfig.java:import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("javaConfig") public class SpringConfig { }这里的
@Configuration
就启用了配置类,之后的@ComponentScan("javaConfig")
是启用了当前包的自动扫描功能。
现在先什么都别做,创建一个应用JavaApp.java试着从容器里获取Bean,很显然,这次就不能用加载XML文件的上下文处理器了,而要加载配置类:
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class JavaApp { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); BaseballCoach baseballCoach = context.getBean("baseballCoach", BaseballCoach.class); System.out.println(baseballCoach.getDailyFortune()); System.out.println(baseballCoach.getDailyWorkout()); context.close(); } }结果完全正常获取了Bean和操作Bean。这是最简单的,通过配置类和开启扫描功能来配置Spring容器。 不过这只是Java配置类中比较讨巧的做法,其本质还是自动扫描这种方法。下边要学习如何通过Java配置类直接配置Bean。
通过Java代码配置Bean
这里我们通过新创建一个SwimCoach并一步一步最终完成注入来学习如何使用Java代码配置Bean和之后的依赖注入。在开始之前看一下步骤:- 在配置类中创建一个方法用于描述Bean
- 注入Bean的依赖
- 载入配置类
- 从容器中获取并使用Bean
@ComponentScan("javaConfig")
,之后创建最简单的SwimCoach类:
public class SwimCoach implements Coach { @Override public String getDailyWorkout() { return "This is SwimCoach work"; } @Override public String getDailyFortune() { return null; } }然后在SpringConfig.java中写如下代码:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SpringConfig { @Bean public Coach swimCoach() { SwimCoach mySwimCoach = new SwimCoach(); return mySwimCoach; } }这里要解释几点:
@Bean
注解表示这个方法定义了一个Bean- 方法的返回类型Coach表示返回的Bean实现的接口
- 方法的名称就是Bean id
- 方法体是创建一个Coach的实现对象并且返回这个对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); SwimCoach swimCoach = context.getBean("swimCoach", SwimCoach.class); System.out.println(swimCoach.getDailyWorkout()); context.close();可以发现
.getDailyWorkout()
已经可以正常工作了。Coach接口的另外一个方法.getDailyFortune()
需要依赖注入,因此我们需要定义更多的Bean来达成依赖注入。
通过Java代码配置Bean的依赖
和之前一样,如果要配置依赖,那么被注入的类也要成为一个Bean,因此先给SwimCoach加上一个接受依赖注入的方法,然后修改配置类://SwimCoach.java public class SwimCoach implements Coach { public FortuneService fortuneService; public SwimCoach(FortuneService fortuneService) { this.fortuneService = fortuneService; } @Override public String getDailyWorkout() { return "This is SwimCoach work"; } @Override public String getDailyFortune() { return fortuneService.getFortune(); } } //SpringConfig.java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SpringConfig { @Bean public FortuneService happyFortuneService() { return new HappyFortuneService(); } @Bean public Coach swimCoach() { SwimCoach mySwimCoach = new SwimCoach(happyFortuneService()); return mySwimCoach; } }现在我们配置了一个新的Bean,是基于HappyFortuneService的Bean。最关键的一点,是在swimCoach这个Bean中,将happyFortuneService()方法传入,这就是依赖注入。 之后通过应用调用一下方法:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); SwimCoach swimCoach = context.getBean("swimCoach", SwimCoach.class); System.out.println(swimCoach.getDailyWorkout()); System.out.println(swimCoach.getDailyFortune()); context.close();发现成功的调用了
.getDailyFortune()
方法,完成了依赖注入。
注入字面量
由于没有了XML文件,现在注入属性需要增加一个配置类的注解@PropertySource
,沿用之前的sport.properties文件,修改配置类:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource("classpath:sport.properties") public class SpringConfig { @Bean public FortuneService happyFortuneService() { return new HappyFortuneService(); } @Bean public Coach swimCoach() { return new SwimCoach(happyFortuneService()); } }这里用
@PropertySource
配置属性来源为classpath下的sport.properties文件,然后还需要在SwimCoach中设置两个域和进行@Value注解,补上getter方法:
import org.springframework.beans.factory.annotation.Value; public class SwimCoach implements Coach { public FortuneService fortuneService; @Value("${foo.email}") private String email; @Value("${foo.team}") private String team; public SwimCoach(FortuneService fortuneService) { this.fortuneService = fortuneService; } @Override public String getDailyWorkout() { return "This is SwimCoach work"; } @Override public String getDailyFortune() { return fortuneService.getFortune(); } public String getEmail() { return email; } public String getTeam() { return team; } }然后在应用中获取一下值看看:
System.out.println(swimCoach.getEmail()); System.out.println(swimCoach.getTeam());成功注入了字面量。
小知识
Spring在运行的时候红色的字体是日志记录,在Spring 5.1版之后,日志级别被调整了,默认将不再输出INFO级别的日志。实际上可以单独再创建一个日志的配置类,通过AnnotationConfigApplicationContext加载多个配置类(依次作为参数),具体不详述了。视频教学没有提到用Java代码配置生命周期管理的方式,这里补充一下。生命周期管理是通过
@Bean
参数来完成的,比如:
@Bean(initMethod = "setup", destroyMethod = "cleanup")
@Scope("prototype")
可以直接添加于Java代码的@Bean
之后,比如将SwimCoach设置成prototype:
@Configuration @PropertySource("classpath:sport.properties") public class SpringConfig { @Bean public FortuneService happyFortuneService() { return new HappyFortuneService(); } @Bean @Scope("prototype") public Coach swimCoach() { return new SwimCoach(happyFortuneService()); } }