spring4.x(八)之第五章--bean的关系及作用域

1. <bean>之间的关系

  1. 继承: 如果多个 <bean> 之间存在相同的配置信息,Spring允许定义个父<bean>,子<bean>将自动继承父<bean>的配置信息
    这里写图片描述
    这里写图片描述
    注:<bean>主要功能是简化子<bean>的配置,一般声明为”abstract=true”,表示这个<bean>不实例化为一个对应的Bean,否则IoC容器会实例化此Bean
  2. 依赖: Spring允许通过depends-on属性显式指定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化前创建好
    这里写图片描述
    注: 如果前置依赖多个Bean,可以通过逗号,空格或分号分隔
  3. 引用:
    假设一个<bean>要引用另一个<bean>的id属性值,可如下配置 :
    这里写图片描述
    注: 由于 spring 并不会在容器启动时对属性配置值进行特殊检查,因此,即使编写错误,也只有到具体调用时才会发现
    Spring为此可以提供了一个<idref>标签,通过它引用另一个<bean>的名字,在容器启动时,Spring负责检查引用关系的正确性,可以提前发现错误:
    这里写图片描述
    注: 如果引用的Bean不存在,在Spring容器启动时,将会提示BeanDefinitionStoreException

2. 整合多个配置文件

在启动Spring容器时,可以通过一个String数组指定多个XML配置文件 ,也可以通过<import>将多个配置文件引入到一个文件中,进行配置文件的集成,这样,在启动Spring容器时,仅需指定这个合并好的配置文件即可。
这里写图片描述
假设在beans1.xml中配置了car1和car2的Bean,在①通过<import>的resource属性引入beans.xml,beans2.xml就拥有了完整的配置信息,Spring容器仅需要通过beans2.xml就可以加载所有的配置信息
如果一个配置文件a.xml定义的<bean>引用了另一个配置文件b.xml定义的<bean>,并不一定需要通过<import>引入b.xml,只需在启动Spring容器时,两个配置文件都在配置文件列表中。
(实际中最好是加载整合的配置文件)

3. Bean作用域

这里写图片描述
注: Spring还允许自定义Bean的作用域,通过org.springframework.beans.factory.config.Scope接口定义新的作用,在通过org.springframework.beans.factory.config.CustomScopeConfigurer这个BeanFactoryPostProcessor注册自定义的Bean作用域

  1. singleton作用域: 在Spring IoC容器中仅存在一个Bean实例,Bean以单实例的方式存在
    Spring将Bean的默认作用域定为singleton,可通过scope属性定义作用域
    这里写图片描述
    指向同一个Bean :
    这里写图片描述
    默认情况下,ApplicationContext容器在启动时,自动实例化所有singleton的Bean并缓存在容器中,虽耗费多点时间,但有两个好处:

    • 对Bean提前进行实例化操作会及早发现潜在的配置问题
    • Bean以缓存的方式保存,当运行时调用该Bean时就无需在实例化了,提高了运行的效率

    如果不希望在容器启动时提前实例化singleton的Bean,可以通过lazy-init属性进行控制

    <bean id="boss1" class="com.smart.scope.Boss" p:car-ref="car" lazy-init="true">

    注: lazy-init=”true”的Bean如果被其他需要提前实例化的Bean引用,Spring将忽略此设置提前实例化

  2. prototype作用域: 每次从容器中调用Bean时,都会返回一个新的实例,即每次调用getBean()时,相当于执行 new xxx()操作
    这里写图片描述
    注: 默认情况下,Spring容器在启动时不实例化prototype的Bean。Spring容器将prototype的Bean交给调用者后,就不再管理其生命周期
  3. 与Web应用环境相关的Bean作用域: ① WebApplicationContext ② request ③ session ④ globalSession

    • 在低版本的Web容器中(Servlet 2.3之前),可以使用HTTP请求过滤器RequestContextFilter进行配置 :
      这里写图片描述
    • 在高版本的Web容器中,利用HTTP请求监听器RequestContextListener进行配置 :
      这里写图片描述

    注: WebApplication初始化时,已经通过ContextLoaderListener(或ContextLoaderServlet)将Web容器与Spring容器进行了整合
    这里写图片描述
    ContextLoaderListener 实现了ServletContextListener监听器接口,ServletContextListener只负责监听Web容器的启动和关闭事件
    RequestContextListener 实现了ServletRequestListener监听器接口,该监听器监听HTTP请求事件,Web服务器接受的每一个请求都会通知该监听器

    • request作用域 : request作用域的Bean对应一个HTTP请求和生命周期,每次HTTP请求都会创建一个新的Bean

      <bean name="car" class="com.smart.scope.Car" scope="request" />

      每次HTTP请求调用car Bean时,Spring容器创建一个新的car Bean,请求处理完毕后,就销毁这个Bean

    • session作用域:

      <bean name="car" class="com.smart.scope.Car" scope="session" />

      car Bean的作用域横跨整个HTTP Session,Session中的所有HTTP请求都共享同一个car Bean。当HTTP Session结束后,实例才被销毁

    • globalSession作用域:

      <bean name="car" class="com.smart.scope.Car" scope="globalSession" />

      类似于session作用域,但仅在Portlet的Web应用中使用。
      Portlet规范定义了全局Session的概念,它被组成Portlet Web应用的所有子Portlet共享。

  4. 作用域依赖问题: 将Web相关作用域的Bean注入singleton或prototype的Bean中,如果没有进行额外配置,将失败。
    这个时候,需要Srping AOP
    这里写图片描述
    car Bean是request作用域,它被singleton作用域的boss Bean引用,为了使boss能够从适当作用域中获取car Bean的引用,需要使用Spring AOP的语法为car Bean配置一个代理类,如②。
    为了能够在配置文件中使用AOP的配置标签,需要在文档声明头中定义aop命名空间,如①。
    当boss Bean在Web环境下调用car Bean时,Spring AOP将启动动态代理智能判断boss Bean位于哪个HTTP请求线程中,并从对应的HTTP请求线程域中获取对应的car Bean
    这里写图片描述
    boss Bean的作用域是singleton,在Spring容器中始终只有一个实例。car Bean作用域为request,每个调用car Bean的HTTP请求都会创建一个car Bean。Spring通过动态代理技术,能够让boss Bean引用到对应HTTP请求的car Bean
    在配置文件中添加<aop:scoped-proxy/>后,注入boss Bean中的car Bean不是原来的car Bean,而是car Bean的动态代理对象。
    这个动态代理是Car类的子类(或实现类,假设Car是接口),Spring在动态代理子类中加入一段逻辑,以判断当前的boss需要获得哪个HTTP请求相关的car Bean
    注: Java只能对接口提供自动代理,要对类提供代理,需要在类路径中加入CGLib的类库,这是Spring将利用CGLib为类生成动态代理的子类

4. FactoryBean

Spring提供了一个FactoryBean工厂类接口,用户可以通过实现该工厂类接口定制实例化Bean的逻辑

FactoBean支持泛型,有3个接口方法:
这里写图片描述
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法

我们希望通过逗号分隔的方式一次性为Car的所有属性指定配置值,可以编写一个FactoryBean来实现
这里写图片描述
有了这个CarFactoryBean,可以在配置文件中使用自定义的配置方式配置Car Bean :
这里写图片描述
当调用getBean(“car”),Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,Spring就调用接口方法getObject()返回工厂类创建的对象。
如果希望获取CarFactoryBean的实例,需要在使用getBean(beanName)方式时显式地在beanName前加上”&”前缀,即getBean(“&car”);

参考: 在IoC容器中装配Bean(精通Spring+4.x++企业应用开发实战 四)

猜你喜欢

转载自blog.csdn.net/yin__ren/article/details/80930183