1. Bean 的类型
用过 IOC
的小伙伴应该都知道如何声明一个 Bean
,最常用的就是使用 @Component
和 @Bean
注解,但是通过这种方式声明的 Bean
都是普通 Bean
,但是在 Spring
中,还有另外一种 Bean
,即工厂 Bean
。
1.1 普通 Bean
使用如下方式声明的:
@Compoent
public class Person {
}
或者:
@Bean
public Person() {
return new Person();
}
1.2 工厂 Bean
一般来说,使用前面两种方式创建普通 Bean
就足够我们使用了。但是,当一个 Bean
的创建比较复杂或者需要依赖特殊的场景创建,这种情况下,使用普通 Bean
的创建方式就满足不了需求了。因此,Spring
提供了 FactoryBean
来让我们使用工厂方法创建对象。
1.2.1 FactoryBean
FactoryBean
是一个接口,用来创建对象的工厂。本身有三个方法:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
/**
* 返回创建的对象
*/
@Nullable
T getObject() throws Exception;
/**
* 返回创建的对象的类型(即泛型类型)
*/
@Nullable
Class<?> getObjectType();
/**
* 创建的对象是单实例Bean还是原型Bean,默认单实例
*/
default boolean isSingleton() {
return true;
}
}
1.2.2 基本使用
public class MyBean implements FactoryBean<SomeObject> {
@Override
public SomeObject getObject() throws Exception {
// 在这里编写创建SomeObject对象的逻辑
return new SomeObject();
}
@Override
public Class<?> getObjectType() {
return SomeObject.class;
}
@Override
public boolean isSingleton() {
return true; // 返回true表示创建的对象是单例的
}
}
然后在配置类中配置:
@Configuration
public class BeanTypeConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
最后从容器中获取:
public class BeanTypeAnnoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanTypeConfiguration.class);
SomeObject object = ctx.getBean(SomeObject.class);
System.out.println(object);
}
}
1.2.3 FactoryBean 创建 Bean 的时机
ApplicationContext
初始化 Bean
的时机默认是容器加载时就已经创建,那 FactoryBean
创建 Bean
的时机呢?
给 SomeObject
和 MyBean
加一个构造方法:
public SomeObject() {
System.out.println("生产了一个SomeObject");
}
public class MyBean implements FactoryBean<SomeObject> {
public MyBean() {
System.out.println("MyBean 被初始化了。。。");
}
}
最后,修改 Main
方法,只需要初始化 IOC
容器:
public class BeanTypeAnnoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanTypeConfiguration.class);
}
}
运行,控制台输出如下:
MyBean 被初始化了。。。
只有 ToyFactoryBean
被初始化,说明 FactoryBean
本身的加载是伴随 IOC
容器的初始化时机一起的。而 SomeObject
并没有打印,说明:FactoryBean
生产 Bean 的机制是延迟生产。
因此重新运行修改前的 Main
方法,控制台都会打印构造方法中的输出。
1.2.4 取出 FactoryBean
前面我们取到的都是 FactoryBean
生产的 Bean
,FactoryBean
本身我们一般也用不到,但是如果要取怎么办呢?按以往的方式如下是取不到的:
ctx.getBean(MyBean.class);
// 或
ctx.getBean("myBean");
真正取 FactoryBean
的方式,需要在 Bean
的 id 前面加 “&” 符号:
ctx.getBean("&myBean");
2. Bean 的作用域
作用域类型 | 描述 |
---|---|
| 单例,一个 |
| 多例,每次获取创建一个 |
| 一次请求创建一个(仅 |
| 一个会话创建一个(仅 Web` 应用可用) |
| 一个 |
| 一个 |
评论区