侧边栏壁纸
博主头像
Leokoの小破站博主等级

行动起来,活在当下

  • 累计撰写 18 篇文章
  • 累计创建 10 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Spring IOC - Bean 的类型和作用域

Leoko
2024-08-16 / 0 评论 / 0 点赞 / 61 阅读 / 9549 字

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 的时机呢?

SomeObjectMyBean 加一个构造方法:

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 生产的 BeanFactoryBean 本身我们一般也用不到,但是如果要取怎么办呢?按以往的方式如下是取不到的:

ctx.getBean(MyBean.class);
// 或
ctx.getBean("myBean");

真正取 FactoryBean 的方式,需要在 Bean 的 id 前面加 “&” 符号:

ctx.getBean("&myBean");

2. Bean 的作用域

作用域类型

描述

singleton

单例,一个 IOC 容器中只有一个【默认值】

prototype

多例,每次获取创建一个

request

一次请求创建一个(仅 Web 应用可用)

session

一个会话创建一个(仅 Web` 应用可用)

application

一个 Web 应用创建一个(仅 Web 应用可用)

websocket

一个 WebSocket 会话创建一个(仅 Web 应用可用)


0

评论区