文章简介:spring 中 bean 的装配有一定规则,在这里进行总结。本文主要讲解一些概念和 java 配置方法。demo 代码见文末。
目录
- 手动装配
- 自动装配 使用@ComponentScan
- 自动装配的歧义性
- 条件生效 Bean
- profile
- bean 作用域
手动装配
手动装配可以通过声明 xml 文件和 java 配置文件两种手段。在这两种方式中,更加推荐使用 java 配置的方式。两种配置不是相互替代的关系,一般将业务相关的配置放到 java 配置中,对于非业务,如数据库等,可以放到 xml 中。
通过使用@Bean 注解方法,可以声明并注册一个以方法名为 name 的 bean。@Bean(name= {“sayAndPlayServiceNewName”, “sayAndPlayService”})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public interface SayAndPlayService {
String say();
String play();
}
public class PeopleSayAndPlayServiceImpl implements SayAndPlayService {
@Override
public String say() {
return "People Service implements say.";
}
@Override
public String play() {
return "People Service implements play.";
}
}
@Configuration
public class SimpleManualwireConfig {
@Bean
public SayAndPlayService sayAndPlayService() {
return new PeopleSayAndPlayServiceImpl();
}
}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes= {org.exfly.demo.config.SimpleManualwireConfig.class})
public class SimpleBeanManualwireTest {
@Autowired
private SayAndPlayService service;
@Test
public void testTestOneAutowiredService() {
Assert.assertEquals("People Service implements say.", service.say());
}
@Test
public void testAnnotationConfigAppContext() {
ApplicationContext context = new AnnotationConfigApplicationContext(org.exfly.demo.config.SimpleManualwireConfig.class);
SayAndPlayService service = (SayAndPlayService) context.getBean("sayAndPlayService");
Assert.assertEquals("People Service implements say.", service.say());
}
}
|
自动装配
使用@ComponentScan 可以自动扫描,@ComponentScan 告诉 Spring 哪个 packages 的用注解标识的类 会被 spring 自动扫描并且装入 bean 容器。自动扫描,会扫描相应包以及子包,并为所有 bean 生成 name,name 命名规则为其类首字母变小写,如 interface UserService 被唯一的 UserServiceImpl 实现,则经过扫描,bean 被声明为 name 为 userServiceImpl。如果接口被多各类实现,需要转到下文消除歧义部分进行了解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public interface SpeakService {
String speak();
}
@Service
public class PeopleSpeakServiceImpl implements SpeakService {
@Override
public String speak() {
return "People speak";
}
}
@Configuration
@ComponentScan(basePackageClasses={org.exfly.demo.service.SpeakService.class})
public class SimpleConfigScanConfig {}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes= {org.exfly.demo.config.SimpleManualwireConfig.class})
public class SimpleBeanManualwireTest {
@Test
public void testAnnotationConfigAppContextAutoScan() {
ApplicationContext context = new AnnotationConfigApplicationContext(org.exfly.demo.config.SimpleConfigScanConfig.class);
SpeakService service = (SpeakService) context.getBean("peopleSpeakServiceImpl");
Assert.assertEquals("People speak", service.speak());
}
}
//如果希望使用@Autowired自动装配,
@RunWith(SpringRunner.class)
@ContextConfiguration(classes= {org.exfly.demo.config.SimpleConfigScanConfig.class})
public class SimpleAutoScanTest {
@Autowired //根据类型进行自动注入
private SpeakService sservice;
@Test
public void testAnnotationConfigAppContextAutoScanAutoWire() {
Assert.assertEquals("People speak", sservice.speak());
}
}
|
@Autowired
可以在属性、构造方法、set 函数中进行自动注入
消除歧义
通过使用@Bean 注解方法,可以声明并注册一个以方法名为 name 的 bean。如果使用@Bean(name= {“sayAndPlayServiceNewName”, “sayAndPlayService”})对 bean 进行命名,可以用不同的名字取用(在@Autowired 处再加一个@Qualifier(“sayAndPlayServiceNewName”));
如果使用@ComponentScan,相应的 Bean 定义需要使用 Component 等进行注解,同时使用@Qualifier(“BeanId”)限定符,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Configuration
public class SimpleManualwireConfig {
@Bean(name={"sayAndPlayServiceNewName", "sayAndPlayService"})
public SayAndPlayService sayAndPlayService() {
return new PeopleSayAndPlayServiceImpl();
}
}
@Service
@Qualifier("peopleSayServ")
public class PeopleSayServiceImpl implements SayService {}
//or
@Service("peopleSayServ")
public class PeopleSayServiceImpl implements SayService {}
//如何使用
@Autowired
@Qualifier("peopleSayServ")
SayService service;
|
条件生效
如下的解释:在当前上下文中,如果 Conditional 注解中的 MagitExistsCondition.matches 方法返回 true,则当前 bean:magicBean 生效。@Profile 和 springboot 自动配置都是基于此种原理实现的。
1
2
3
4
5
6
7
8
9
10
11
|
@Bean
@Conditional(MagitExistsCondition.class)
public MagicBean magicBean(){
return new MagitBean();
}
public class MagitExistsCondition implements Condition {
boolean matches(ConditionContext ctxt, AnnotatedTypeMetadat metadate){
Environment env = ctxt.getEnvironment();
return env.containsProperty("magic");
}
}
|
@Profile
bean 作用域
- Singleton 默认 只创建一个实例
- Prototype 每次创建新的实例
- Session 每个会话创建一个实例
- Request 每个请求创建一个实例
使用@Scope 进行配置即可
1
2
3
|
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad{}
|
运行时值注入
以后补充
其他
项目代码