美文网首页
六、容器中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