上文我们简单的通过注解类+@bean注解的方式将第三方类注入到了IOC容器进行管理,那么本文我们来详细介绍@bean的用法。
1. @Bean生成Bean的Name问题
@Bean注解源码:
public @interface Bean {
//前两个注解可以指定Bean的标识
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
//autowireCandidate 属性来指示该 Bean 是否候选用于自动装配。
//autowireCandidate 属性默认值为 true,表示该 Bean 是一个默认的装配目标,
//可被候选用于自动装配。如果将 autowireCandidate 属性设置为 false,则说明该 Bean 不是默认的装配目标,不会被候选用于自动装配。
boolean autowireCandidate() default true;
//指定初始化方法
String initMethod() default "";
//指定销毁方法
String destroyMethod() default "(inferred)";
}
通过源码可以看到,我们可以通过name或者value来为组件进行赋值。
指定@Bean的名称:
@Configuration
public class AppConfig {
@Bean("myThing") //指定名称
public Thing thing() {
return new Thing();
}
}
@Bean
注释注释方法。使用此方法在指定为方法返回值的类型的 ApplicationContext
中注册 Bean 定义。缺省情况下,Bean 名称与方法名称相同。下面的示例演示 @Bean
方法声明:
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
前面的配置完全等同于下面的Spring XML:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
2. @Bean 初始化和销毁方法指定
@Bean
注解支持指定任意初始化和销毁回调方法,非常类似于 Spring XML 在 bean
元素上的 init-method
和 destroy-method
属性,如以下示例所示:
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
3. @Bean Scope作用域
可以指定使用 @Bean
注释定义的 bean 应具有特定范围。您可以使用在 Bean 作用域部分中指定的任何标准作用域。singleton表示单例模式,prototype表示多例。
默认作用域为 singleton
,但您可以使用 @Scope
注释覆盖此范围,如以下示例所示:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
4. @Bean方法之间依赖
4.1 场景说明
在实际应用场景中,我们可能需要在一个@bean方法中用到另一个bean组件,这样,bean方法之间就存在依赖关系。那么,如何处理这种依赖关系?
例如,当前有以下两个组件:
public class HappyMachine {
private String machineName;
public String getMachineName() {
return machineName;
}
public void setMachineName(String machineName) {
this.machineName = machineName;
}
}
public class HappyComponent {
//引用新组件
private HappyMachine happyMachine;
public HappyMachine getHappyMachine() {
return happyMachine;
}
public void setHappyMachine(HappyMachine happyMachine) {
this.happyMachine = happyMachine;
}
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
可以看到,HappyComponent 中包含HappyMachine 类型的属性,两者存在依赖关系。
4.2 方法一
直接调用方法返回 Bean 实例:在一个 @Bean
方法中直接调用其他 @Bean
方法来获取 Bean 实例,虽然是方法调用,也是通过IoC容器获取对应的Bean,例如:
@Configuration
public class JavaConfig {
@Bean
public HappyMachine happyMachine(){
return new HappyMachine();
}
@Bean
public HappyComponent happyComponent(){
HappyComponent happyComponent = new HappyComponent();
//直接调用方法即可!
happyComponent.setHappyMachine(happyMachine());
return happyComponent;
}
}
可以看到,先使用@Bean将happyMachine注入IOC容器,之后在happyComponent的bean方法中,可以调用happyMachine的bean方法即可。
4.3 方法二
参数引用法:通过方法参数传递 Bean 实例的引用来解决 Bean 实例之间的依赖关系,例如:
import com.atguigu.ioc.HappyComponent;
import com.atguigu.ioc.HappyMachine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
public HappyMachine happyMachine(){
return new HappyMachine();
}
@Bean
public HappyComponent happyComponent(HappyMachine happyMachine){
HappyComponent happyComponent = new HappyComponent();
//赋值
happyComponent.setHappyMachine(happyMachine);
return happyComponent;
}
}
注意:
可以直接在形参列表接收IoC容器中的Bean!
-
情况1: 如果只有一个bean,直接指定类型即可
-
情况2: 如果有多个bean,(HappyMachine 名称 ) 形参名称等于要指定的bean名称。
例如:
@Bean
public Foo foo1(){
return new Foo();
}
@Bean
public Foo foo2(){
return new Foo()
}
@Bean
public Component component(Foo foo1 / foo2 通过此处指定引入的bean)