一半夜间想的查漏补缺 , Spring 中 Bean 之间的因问题。六、容器中Bean的生命周期。

老是看开都见面发现自己的不足 .

赖关系注入下的行为:

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接口污染代码,是低侵入式设计。

      当一个 singten 的 Bean 依赖一个 prototype 的 Bean 时 ,
如果不加注意 , 会发生有出乎意料的作业 , prototype 变为了 singten 了 ,
这是干吗呢 ?

      这是 Spring 容器本身的特性 , 当初始化 Spring 容器时 ,
容器会预初始化容器被颇具的 singleton 的 Bean , 由于 singleton Bean
依赖让 propertype Bean , 因此 , 容器在初始化 singleton Bean
之前见面优先创造 propertype Bean , 然后用创造好之 propertype Bean
作为性能注入到 singleton Bean 中 , 一旦容器创建好 singleton Bean ,
容器在它们销毁之前都不会也她第二坏注入 propertype Bean , 这样一来 ,
propertype Bean 却展现出了 singleton 的行事了 , 与设计之初衷背道而驰 .

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实现该抽象类,并也底实现抽象方法。

  • 放弃依赖注入 : singleton 作用域的 Bean 每次都需要 propertype
    作用域的 Bean 时, 主动往容器请求新的 Bean 实例 ,
    即可保证每次注入的 Bean , 都是新的 propertype Bean 的实例 . (
    不推荐 )
  • 采用方式注入 : 使用 <lookup-method>
    标签指定一个抽象方法以及 propertype Bean . 具体落实就是将 singleton
    Bean 的切近声明也一个空洞类 , 并提供一个虚无方法 ,
    这个抽象方法就是是用来注入 propertype Bean 的 . ( 推荐以 )

下面举一个板栗 :

       一个猎人 , 有捕猎的职能 , 每次打猎都牵动达猎狗 ,
但是历次带的猎狗都不比 , 也即是顺应地方的一个是 singten , 一个是
prototype , 猎人依赖猎狗 .

 

1

注 : 利用方式注入的原形使用了代理 , 分为有限种代理 , JDK 代理及
cglib 代理 , 如果目标抽象类实现了接口 , Spring 容器会下 JDK
代理实现抽象方法 , 如果目标类没有兑现了接口 , Spring 会采用 cglib 代理
, 实现该抽象方法 .

相关文章