spring详解(三)

5.深入理解Spring容器中的Bean

抽象Bean

所有的抽象Bean,就是是定abstract属性为true的Bean,抽象Bean不能被实例化,抽象Bean的价值在于被继承

使用子Bean

随着应用规模的增大,Spring配置文件的增长速度更快。当应用中的组件越来越多,,Spring中的Bean配置也随之大幅度增加。 就会出现一种现象:有一批配置Bean的信息完全相同,只有少量的配置不同。怎么解决呢? 这时候就可以用Bean的继承来解决。

注意子Bean无法从父Bean继承如下属性:
depends-on,aotuwirwe,dependency-check,singleton,scope,lazy-iniyt这些属性总是子Bean定义,或采用默认值。
通过为一个 元素指定parent属性,即可指定该Bean是一个子Bean。

Bean继承与java中继承的区别

Spring 中的bean 继承与Java中的继承截然不同。前者是实例与实例之间参数值的延续,后者则是从一般到特殊的细化。前者是对象与对象之间的关系,后者是类与类之间的关系。

因此, Spring 中bean 的继承和Java 中bean 的继承有如下区别:

  • Spring 中的子bean 和父bean 可以是不同类型,但在Java 中的,子类是对父类的加强,是一种特殊的父类。
  • Spring 中bean 的继承是实例之间的关系,主要表现为参数值的延续:而Java 中的继承是类与类之间的关系,主要表现为方法及属性的延续。
  • Spring 中子bean 不可作父bean 使用,不具备多态'性:而Java 中的子类实例完全可当成父类实例使用。

  • Bean的生命周期

    ①singleton与prototype的区别:

    singletonSpring可以精确的知道该Bean何时被创建、初始化、销毁。对于singleton作用域的Bean,每次客户端请求Spring容器总会返回一个共享的实例。
    prototypeSpring容器仅仅负责创建Bean,当容器创建了Bean的实例后,Bean实例完全交给客户端代码管理,容器不在跟踪其生命周期。每次客户端请求prototype作用域的Bean,都会为他创建一个新的实例.

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

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

  • 使用init-method属性指定某个方法在Bean全部属性依赖关系设置结束后自动执行。使用这种方法不需要将代码与Spring的接口耦合在一起,代码污染少;

  • 实现Initializing接口,该接口有一个方法void afterPropertiesSet() throws Exception,虽然实现次接口一样可以在Bean全部属性设置成功后执行特定的行为,但是污染了代码,是侵入式设计,因此不推荐使用。

  • 注意如果采用init-method属性指定初始化方法,又实现InitializingBean接口来指定初始化方法,先执行initializingBean接口中定义的方法,再执行init-method属性指定的方法。

    ③Bean销毁之前行为:

    与定制初始化相似,Spring也提供两种方式定制Bean实例销毁之前的特定行为,如下:
    使用destroy-method属性:
    实现DisposableBean接口:
    注意如果即采用destroy-method属性指定销毁之前的方法,又实现DisposableBean接口来指定指定销毁之前的方法,与②类似。

    ④default-init-method与default-destroy-method属性

    指定了所有的Bean都会执行此方法,而不是单个的Bean。


    协调作用域不同步的Bean

    描述:

    如singleton作用域Bean依赖prototype作用域的Bean,当spring容器初始化时,他会初始化容器中所有的 singleton Bean ,此时prototype Bean 被创建出来,并注入到singleton Bean中,此处当singleton Bean 被创建后,它就持有一个prototype Bean,容器不再为singleton Bean 执行注入了.

    由于singleton Bean具有单例行为,当客户端多次请求singleton Bean 时,Spring 返回给客户端的是同一个实例,这不存在任何问题。问题是:如果客户端多次请求singleton Bean 并调用prototype Bean 的方法时,始终都是调用同一个prototype Bean实例,这就违反了prototype Bean 的初衷了。

    解决方法:
    1.部分放弃依赖注入:singleton作用域的Bean每次需要prototype作用域的Bean,则主动向容器请求新的Bean实例。

    2.利用方法注入。利用lookup方法注入可以让Spring 容器重写容器的Bean 的抽象或具象方法。

    第一种方案肯定是不好的,代码主动请求新的Bean实例,必然会导致与Spring API耦合,造成代码严重污染。通常情况下采用第二中方式。
    方法注入通常使用lookup方法注入,利用lookup方法注入可以让Spring容器重写容器中Bean的抽象方法或具体方法,返回查找容器中的其他 Bean,被查找的Bean通常是non-singleton Bean(尽管也可以是singleton).

    public abstract class Chinese
    implements Person
    {
    public Chinese()
    {
    System.out.println("Spring实例化主调bean:Chinese实例...");
    }
    //定义一个抽象方法,该方法将由Spring负责实现
    public abstract Axe getAxe();
    public void useAxe()
    {
    System.out.println("正在使用 " + getAxe()
    + "砍柴!");
    System.out.println(getAxe().chop());
    }
    }

    >`在Spring配置文件中配置:`
    >```
      
      
      
             
          
          
              
              
          
      
    
    public class BeanTest  
    {  
        public static void main(String[] args)  
        {  
            ApplicationContext ctx = new   
                ClassPathXmlApplicationContext("bean.xml");  
            Person p = ctx.getBean("chinese" , Person.class);  
            //两次通过p对象使用Axe对象  
            p.useAxe();  
            p.useAxe();  
        }  
    }  
    

    你可能感兴趣的:(spring详解(三))