浅谈bean的实例化、生命周期和依赖注入

272 阅读4分钟

1. bean的管理,比较重要的知识点

bean默认使用单例模式进行对象的管理,因此不仅IoC是单例的,IoC里面的对象也是单例的。可以使用 scope关键字控制管理的对象是单例(singleton)还是多例(prototype)。

2. bean 的实例化方式

方式一:构造方法实例化bean

通过构造方法构造对象是使用反射的方式,调用的是该对象的无参构造方法,把该对象的无参构造方法改成 private也可以通过反射调用,但是如果重写一个有参构造方式,那么bean在构造对象的时候就找不到相应的方法,便会报错。因此让bean托管的对象一定得保证有无参构造器。

<bean id="bookDao" class="com.dao.impl.BookDaoImpl"/>

方式二:使用静态工厂实例化bean

需要在配置中把 class设置为工厂类,把 factory-method设置为工厂函数:

<bean id="orderDao" class="com.factory.OrderDaoFactory" factory-method="getOrderDao"/>

方式三:使用实例工厂实例化bean

<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>    
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

方式四:使用FactoryBean实例化bean

<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

相当于对方式三做了个简化,使用非静态函数 getObject()默认为 factory-method

需要注意的是 UserDaoFactoryBean 作为工厂类,需要继承 FactoryBean<T>接口,接口三个函数:

T getObject() throws Exception;​ 
  
Class<?> getObjectType();​   

public boolean isSingleton() {    
    return true;
}

其中 isSingleton()方法可以设置实例化的对象是否为单例,但是在配置中通过 scope 也能设置对象是否为单例,当两个都配置了的话,只有两个地方都配置了单例,才会是单例。

  isSingleton和scope不同组合条件下,bean的类型

3. bean的生命周期

创建bean的初始化和销毁时执行的函数:

方法一、通过 init-methoddestroy-method标签。

<bean id="bookDao" class="com.study.spring.Dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" />

方法二、通过继承接口实现,不用带标签了

public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {    
    @Override    
    public void save(String data) {        
        System.out.println("Save " + data + " success!\n");    
    }    

    // 销毁时的操作    
    @Override    
    public void destroy() {        
        System.out.println("service destroy...");    
    }​    
    // 初始化时候的操作
    @Override    
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init...");    
    }
}

假如两种方式同时设置,则两种方法都会分别调用。

对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:

初始化容器:

  • 1.创建对象(内存分配)

  • 2.执行构造方法

  • 3.执行属性注入(set操作)

  • 4.执行bean初始化方法

使用bean :

  • 1.执行业务操作 关闭/销毁容器

  • 2.执行bean销毁方法

4. 依赖注入

方法一、通过构造器注入,使用 constructor-arg标签,类中提供构造器

基本数据类型用name指定构造器形参,基本数据类型用 value指定值,对象用 ref指定 bean id

<bean id="bookDao" class="com.study.spring.Dao.impl.BookDaoImpl" >    
    <constructor-arg name="connectNum" value="11"></constructor-arg>
    <constructor-arg name="mysqlName" value="mysql-5.0"></constructor-arg>
</bean>
<bean id="userDao" class="com.study.spring.Dao.impl.UserDaoImpl" />
<bean id="bookService" class="com.study.spring.service.impl.BookServiceImpl">
    <constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
    <constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。 ref属性指向的是spring的IOC容器中其他bean对象。

通过 indextype 设置参数在构造函数中的位置或者类型,进行对应。

<constructor-arg type="int" value="11"></constructor-arg>
<constructor-arg type="String" value="mysql-5.0"></constructor-arg>

<constructor-arg index="0" value="11"></constructor-arg>
<constructor-arg index="1" value="mysql-5.0"></constructor-arg>

方法二、通过setter注入,需要类提供setter方法

变量名用name指定,基本数据类型用value指定值,对象用ref标签指定bean id

<bean ...>    
    < property name="" value=""/>    
    < property name="" ref=""/>   
</bean>

依赖注入方式的选择

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现 强制依赖指对象在创建的过程中必须要注入指定的参数

  2. 可选依赖使用setter注入进行,灵活性强 可选依赖指对象在创建过程中注入的参数可有可无

  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相 对严谨

  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选 依赖的注入

  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注 入

  6. 自己开发的模块推荐使用setter注入

5.依赖自动装配

  • 按类型(常用)

  • 按名称

  • 按构造方法

  • 不启用自动装配