IOC基础-Bean的理解与掌握

99 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情

本文会讲到常见的几种Bean类型、Bean的作用域、实例化方式、生命周期等内容。

Bean的类型划分主要根据Bean的生成方式来的:普通Bean和工厂Bean两种。

普通Bean

@Component
public class Child{}
//或者下面这种
@Bean
public Child child(){
  return new Child();
}

再或者xml里面的 <bean class="com.linkedbear.spring.bean.a_type.bean.Child"/>,这些都是普通Bean。

工厂Bean

工厂Bean是需要实现FactoryBean接口的,该接口下面有三个方法:

        getObject(); //返回创建的对象
        getObjectType();//返回创建的对象的类型
        isSingleton();//是否是原型Bean

工厂Bean生产Bean的时候我们只需要重点去写getObject这个方法就行,返回值就是我们的Bean类型。假设有一个Toy类型的抽象玩具类,它有两个继承子类Car和Ball,我们可以根据传入的字符串是car还是ball来决定创建的是哪个玩具,这个实现很简单,就不详细去说了。

public Toy getObject() throws Exception {
    switch (child.getWanToy()){
        case "ball":
            return new Ball("ball");
        case "car":
            return new Car("car");
        default:
            return null;
    }
}

当然,上述只是第一步,接下来我们需要去注册工厂类,就像我们在xml或者使用注解来注册普通Bean那样容易。

工厂Bean创建Bean的时机

普通Bean和工厂Bean本身的加载都是伴随IOC容器初始化的,这句话什么意思呢?普通Bean和工厂Bean都当做简单的Bean去看就行了,初始化是在IOC容器初始化的时候完成的,即执行了类似下属语句:

ApplicationContext ctx = new AnnotationConfigApplicationContext(ToyFactoryBeanConfig.class);

工厂Bean创建的Bean在这个时候是不会初始化的,这个初始化过程是在容器拿工厂生产的Bean的时候才进行初始化的,工厂Bean创建Bean的时机是延时创建。
大家可以自己写个案例测试测试,会有更深的印象~

Bean的作用域

spring中Bean的作用域指的是singleton(单例)、prototype(原型)、requestWeb(应用一次请求创建一个)、session(一个会话创建一个)、application(一个web应用一个)、websocket(一个websocket会话创建一个)。

singleton单例Bean指的是一个IOC容器只有一个; prototype原型Bean则是创建一个就有一个,IOC容器里可以有多个这样的Bean。其他几个这里就先不提了。
我们创建的Bean默认都是单例的,需要改成原型Bean的话:

  • 对于使用注解的方式,加个@Scope("prototype")注解就行。
  • xml的方式,bean标签里加上scope属性,对应值设为prototype即可。

Bean的实例化

普通Bean和工厂Bean的实例化创建Bean的方式就不再累赘了,我们只说重点!

借助静态工厂创建Bean

举个例子,首先我们有Car这个类如下:

public class Car {
    public Car() {
        System.out.println("Car go go go");
    }
}

接着我们写个简单的静态工厂来生成这个Car:

public class CarStaticFactory {
    public static Car getCar() {
        return new Car();
    }
}

配置xml,我们将Bean静态类工厂的创建方法放到IOC容器中(Bean工厂本身其实不在IOC中,这个大家可以自己测试一下),xml中"class"+"factory-method":

<bean id="car" class="com.linkedbear.spring.bean.c_instantiate.bean.CarStaticFactory" factory-method="getCar"/>
实例工厂创建Bean

实例工厂和静态工厂的面上区别是:实例工厂不带static修饰。
xml创建的方式上也是有区别的,xml创建如下:

 <bean id="carInstanceFactory" class="com.spring.bean.CarInstanceFactory"/>
 <bean id="car" factory-bean="carInstanceFactory" factory-method="getCar"/>

这里没讲注解式,是因为注解式的太简单了,只要在工厂类上加个@Bean注解就行了。

Bean的生命周期

Bean的生命周期指的是Bean的创建(实例化)、初始化、运行、销毁、回收几个阶段。

Spring能插上手的Bean的生命周期阶段是初始化和销毁阶段。下面简单讲解几种Spring干预这两个阶段的方法。

  • 创建一个类,定义两个方法,分别用@Bean的init-method参数和destroy-method参数指明方法,或者在xml的bean标签里加上init-method和destroy-method两个属性,值对应类中的初始化方法和销毁方法。
  • @PostConstruct和@PreDestory这个只需要在类的方法上加上这两个注解就可以指明初始化方法和销毁方法。
  • 创建一个类并实现InitializingBean和DisposableBean两个类的初始化方法和摧毁方法

三者并存情况下的优先顺序:@PostConstructInitializingBeaninit-method
最后是三种方式的对比,如图:

image.png