目录

Spring Beans的装配规则总结

文章简介:spring 中 bean 的装配有一定规则,在这里进行总结。本文主要讲解一些概念和 java 配置方法。demo 代码见文末。

目录

  • 手动装配
    • 使用@Bean
  • 自动装配 使用@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{}

运行时值注入

以后补充

其他

项目代码