美文网首页
六、容器中Bean的生命周期

六、容器中Bean的生命周期

作者: 数独题 | 来源:发表于2017-03-05 10:14 被阅读37次

依赖关系注入之后的行为:

Spring提供两种方式在Bean的全部属性设置成功后执行特定的行为:

  • 使用init-method属性。
  • 实现InitializingBean接口。
    第一种方式:使用init-method属性指定某个方法在Bean全部依赖关系设置结束后自动执行。使用这种方式不需要讲代码与Spring的接口耦合在一起,代码污染小。
    第二种方式:让Bean类实现initlializingBean接口,该接口提供一个方法void afterPropertiesSet() thorows Exception;Spring会在为该Bean注入依赖关系之后,调用该Bean所实现的afterPropertiesSet()方法。

Chinese.java

package entity;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import inter.Axe;
import inter.Persion;

public class Chinese implements Persion,InitializingBean,BeanNameAware,ApplicationContextAware {

    private Axe axe;
    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        System.out.println("======setApplicationContext=======");
        
    }

    public Chinese()
    {
        System.out.println("Spring实例化主调Bean:Chinese实例...");
    }
    @Override
    public void setBeanName(String arg0) {
        // TODO Auto-generated method stub
        System.out.println("=============setBeanName===============");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("正在执行初始化方法afterPropertiesSet.....");
    }

    @Override
    public void useAxe() {
        // TODO Auto-generated method stub
        System.out.println(axe.chop());
    }
    public void setAxe(Axe axe)
    {
        System.out.println("Spring调用setAxe()执行依赖注入...");
        this.axe=axe;
    }

    public void init()
    {
        System.out.println("正在执行初始化方法init....");
    }
}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd" >
     <bean id="steelAxe" class="entity.SteelAxe"/>
     
     <!-- 配置ChineseBean,使用init-method="init" -->
     <bean id="chinese" class="entity.Chinese" init-method="init">
        <property name="axe" ref="steelAxe" />
     </bean>
</beans>

输出

Spring实例化主调Bean:Chinese实例...
Spring调用setAxe()执行依赖注入...
=============setBeanName===============
======setApplicationContext=======
正在执行初始化方法afterPropertiesSet.....
正在执行初始化方法init....
钢斧砍柴真快!

如果某个类实现了Initializing接口,当该Bean所有的依赖关系被设置完成后,Spring容器会自动调用该Bean实例的setPropertiesSet()方法;其执行结果与采用init-method属性指定生命周期一样。但现实Initializing接口污染代码,是低侵入式设计。

Bean销毁之前的行为:

Spring提供了两种定制Bean实例销毁之前的特定行为:

  • 使用destroy-method属性。
  • 实现DisposableBean接口。
    第一种方式:使用destroy-method属性指定某个方法在Bean销毁之前自动被执行,使用这种方式不需将代码与Spring的接口耦合在一起,代码污染低。
    第二种方式:让Bean类实现DisposableBean接口,实现该接口提供的方法void destroy() throws Exception。

配置文件与实例化之后的beans.xml文件类似。

协调作用域不同步的Bean:

当singleton作用域的Bean依赖于prototype作用域的Bean时,会产生不同步的现象,解决该问题有两种思路:

  • 放弃依赖注入:singleton作用域的Bean每次需要prototype作用域的Bean时,主动向容器请求新的Bean实例,即可保证每次注入的prototype Bean实例都是最新的实例。
  • 利用方法注入:方法注入通常采用lookup方法注入。

为了使用lookup方法注入,大致需要两步

  • 将调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean。
  • 在<bean.../>元素中添加<lookup-method.../>子元素让Spring为调用者Bean的实现类实现指定的抽象方法。

Chinese.java

public abstract class Chinese implements Persion
{
     private Dog dog;
     //定义抽象方法,该方法用于获取被依赖的Bean
     public abstract Dog getDog();
     public void hunt()
     {
           System.out.println("我带着"+getDog()+"出去打猎");
           System.out.println(getDog().run());
     }
}

使用<lookup-method.../>元素需要指定如下两个属性:

  • name:指定需要让Spring实现的方法。
  • bean:指定Spring实现该方法的返回值。

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd" >
    
   
     <bean id="chinese" class="entity.Chinese">
       <!-- Spring只要检测到lookup-method元素,Spring会自动为该元素的name属性所指定的方法提供实现体 -->
        <lookup-method name="getDog" bean="gunDog"/>
     </bean>
     
     <!-- 指定gunDog Bean的作用域为prototype,希望程序每次使用该Bean时都得到不同的实例 -->
     <bean id="gunDog" class="entity.GunDog" scope="prototype">
        <property name="name" value="旺财"/>
     </bean>
</beans>

Spring会采用运行时动态增强的方式来实现<lookup-method.../>元素所指定的抽象方法,如果目标抽象类(如上Chinese类)实现过接口,Spring会采用JDK动态代理来实现该抽象类,并为之实现抽象方法;如果抽象类没有实现过接口,Spring会采用cglib实现该抽象类,并为之实现抽象方法。

相关文章

网友评论

      本文标题:六、容器中Bean的生命周期

      本文链接:https://www.haomeiwen.com/subject/kessgttx.html