上文我们简单的通过注解类+@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 {@Beanpublic 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 {@Beanpublic HappyMachine happyMachine(){return new HappyMachine();}@Beanpublic 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 {@Beanpublic HappyMachine happyMachine(){return new HappyMachine();}@Beanpublic HappyComponent happyComponent(HappyMachine happyMachine){HappyComponent happyComponent = new HappyComponent();//赋值happyComponent.setHappyMachine(happyMachine);return happyComponent;}}
注意:
可以直接在形参列表接收IoC容器中的Bean!
-
情况1: 如果只有一个bean,直接指定类型即可
-
情况2: 如果有多个bean,(HappyMachine 名称 ) 形参名称等于要指定的bean名称。
例如:
@Beanpublic Foo foo1(){return new Foo();}@Beanpublic Foo foo2(){return new Foo()}@Beanpublic Component component(Foo foo1 / foo2 通过此处指定引入的bean)