配置-代码
1. 前言
Spring 的代码配置 Java-configuration,核心是通过@Configuration
修饰的配置类搭配@Bean
修饰的方法来支持的:
The
@Bean
annotation is used to indicate that a method instantiates, configures, and initializes a new object to be managed by the Spring IoC container.Annotating a class with
@Configuration
indicates that its primary purpose is as a source of bean definitions. Furthermore,@Configuration
classes let inter-bean dependencies be defined by calling other@Bean
methods in the same class.以下两者等价:
代码配置
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
XML 配置
<beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans>
When @Configuration
classes are provided as input, the @Configuration
class itself is registered as a bean definition and all declared @Bean
methods within the class are also registered as bean definitions.
When @Component
and JSR-330 classes are provided, they are registered as bean definitions, and it is assumed that DI metadata such as @Autowired
or @Inject
are used within those classes where necessary.
2. Full @Configuration vs lite @Bean mode?
详见 配置-注解:@Configuration vs @Component
3. 构建 IoC 容器
3.1 实例化 IoC 容器——AnnotationConfigApplicationContext
两种方式。
In much the same way that Spring XML files are used as input when instantiating a ClassPathXmlApplicationContext
, you can use @Configuration
classes as input when instantiating an AnnotationConfigApplicationContext
.
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
You can instantiate an AnnotationConfigApplicationContext
by using a no-arg constructor and then configure it by using the register()
method.
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
3.2 设置包扫描路径
除了在 @Configuration
配置类上使用 @ComponentScan
注解外,也可以使用 AnnotationConfigApplicationContext
暴露的scan(String...)
方法。以下两种方式等价:
注解:
@Configuration @ComponentScan(basePackages = "com.acme") public class AppConfig { // ... }
scan 方法:
public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.scan("com.acme"); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); }
Remember that
@Configuration
classes are meta-annotated with@Component
, so they are candidates for component-scanning.In the preceding example, assuming that
AppConfig
is declared within thecom.acme
package (or any package underneath), it is picked up during the call toscan()
. Uponrefresh()
, all its@Bean
methods are processed and registered as bean definitions within the container.
3.3 AnnotationConfigWebApplicationContext
A WebApplicationContext
variant of AnnotationConfigApplicationContext
is available with AnnotationConfigWebApplicationContext
. You can use this implementation when configuring the Spring ContextLoaderListener
servlet listener, Spring MVC DispatcherServlet
, and so forth.
4. @Profile, @Conditional
It is often useful to conditionally enable or disable a complete @Configuration
class or even individual @Bean
methods, based on some arbitrary system state.
One common example of this is to use the @Profile
annotation to activate beans only when a specific profile has been enabled in the Spring Environment
(see Bean Definition Profiles for details).
The @Profile
annotation is actually implemented by using a much more flexible annotation called @Conditional
. The @Conditional
annotation indicates specific org.springframework.context.annotation.Condition
implementations that should be consulted before a @Bean
is registered.
package org.springframework.context.annotation;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
String[] value();
}
package org.springframework.context.annotation;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}