• spring基础——DI(四)


      接上一篇《spring基础——DI(三)》

      3.5 引用其他bean

        上一篇已经介绍了注入常量、集合等基本数据类型和集合数据类型,承接上文继续介绍注入依赖bean及注入内部bean。引用其他bean的步骤与注入常量的步骤一样,可以通过构造器注入及setter注入引用其他bean。

    • 构造器方式注入:通过constructor-arg标签ref属性来引用其他bean,这是最简化的配置:或者通过constructor-arg标签的子ref标签来引用其他bean。

         

               

    • setter方式注入:通过property标签的ref属性来引用其他bean,或者通过property标签的子ref标签来引用其他bean。

        

        

     1 <!-- 定义依赖Bean -->
     2 <bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
     3 <!-- 通过构造器注入 -->
     4 <bean id="bean1" class="cn.javass.spring.chapter3.bean.HelloApiDecorator">
     5   <constructor-arg index="0" ref="helloApi"/>
     6 </bean>
     7 <!-- 通过构造器注入 -->
     8 <bean id="bean2" class="cn.javass.spring.chapter3.bean.HelloApiDecorator">
     9    <property name="helloApi"><ref bean=" helloApi"/></property>
    10 </bean>
     1 package cn.javass.spring.chapter3.bean;
     2 import cn.javass.spring.chapter2.helloworld.HelloApi;
     3 public class HelloApiDecorator implements HelloApi {
     4 private HelloApi helloApi;
     5   //空参构造器
     6    public HelloApiDecorator() {
     7   }
     8   //有参构造器
     9    public HelloApiDecorator(HelloApi helloApi) {
    10    this.helloApi = helloApi;
    11 }
    12 public void setHelloApi(HelloApi helloApi) {
    13    this.helloApi = helloApi;
    14    }
    15    @Override
    16    public void sayHello() {
    17    System.out.println("==========装饰一下===========");
    18    helloApi.sayHello();
    19    System.out.println("==========装饰一下===========");
    20    }
    21 }
     1 @Test
     2 public void testBeanInject() {
     3    BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/beanInject.xml");
     4    //通过构造器方式注入
     5    HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);
     6    bean1.sayHello();
     7    //通过setter方式注入
     8    HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class);
     9    bean2.sayHello();
    10 }
    • 其他引用方式:除了基本配置除外,spring还提供了两种更高级的配置方式:<ref local="">、<ref parent="">。<ref local="">用于引用通过id属性指定的bean,它能利用xml解析器的验证功能在读取配置文件时来验证引用的bean是否存在。

              <ref parent="">用于引用父容器的bean,不引用当前容器的bean。

                                              

       注:关于父子容器相关概念参照《Spring-SpringMVC父子容器&AOP使用总结(转)》。

      3.6 内部bean定义

        内部bean就是在property或constructor-arg内部通过bean标签定义bean。该bean不管是否指定id或name,该bean都会有唯一的匿名标识符,而且不能指定别名,该内部bean对其他bean都不可见。

        

    1 <bean id="bean" class="cn.javass.spring.chapter3.bean.HelloApiDecorator">
    2   <property name="helloApi">
    3     <bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
    4   </property>
    5 </bean>
    1 @Test
    2 public void testInnerBeanInject() {
    3   ApplicationContext context = new ClassPathXmlApplicationContext("chapter3/innerBeanInject.xml");
    4   HelloApi bean = context.getBean("bean", HelloApi.class);
    5   bean.sayHello();
    6 }

      3.7 注入null

        spring通过value标签或value属性注入常量值,所有注入的数据都是字符串,那如何注入null值?spring提供了null标签。

    1 <bean class="...HelloImpl4">
    2   <property name="message"><null/></property>
    3   <property name="index" value="1"/>
    4 </bean>

      3.8 简写配置

        接下来总结以下依赖注入配置及简写形式:

    • 构造器注入:

        1)常量值:

    1 <!--简写-->
    2 <constructor-arg index="0" value="常量"/>
    3 <!--全写-->
    4 <constructor-arg index="0"><value>常量</value></constructor-arg>

        2)引用:

    1 <!--简写-->
    2 <constructor-arg index="0" ref="引用"/>
    3 <!--全写-->
    4 <constructor-arg index="0"><ref bean="引用"/></constructor-arg>
    • setter注入:

        1)常量值:

    1 <!--简写-->
    2 <property name="message" value="常量"/>
    3  <!--全写-->
    4 <property name="message"><value>常量</value></ property>

        2)引用:

    1 <!--简写-->
    2 <property name="message" ref="引用"/>
    3  <!--全写-->
    4 <property name="message"><ref bean="引用"/></ property>

        3)数组:<array>没有简写形式

        4)列表:<list>没有简写形式

          5)集合:<set>没有简写形式

       6)字典:

     1 <!--简写-->
     2  <map>
     3    <entry key="键常量" value="值常量"/>
     4    <entry key-ref="键引用" value-ref="值引用"/>
     5  </map>
     6 <!--全写-->
     7 <map>
     8   <entry><key><value>键常量</value></key><value>值常量</value></entry>
     9   <entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
    10 </map>

        7)Properties:没有简写形式

    • 使用p命名空间简化setter注入:  

        使用p命名空间来简化setter配置如下

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4  xmlns:p="http://www.springframework.org/schema/p"
     5  xsi:schemaLocation="
     6  http://www.springframework.org/schema/beans
     7  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     8   <bean id="bean1" class="java.lang.String">
     9      <constructor-arg index="0" value="test"/>
    10   </bean>
    11   <bean id="idrefBean1" class="cn.javass.spring.chapter3.bean.IdRefTestBean" p:id="value"/>
    12    <bean id="idrefBean2" class="cn.javass.spring.chapter3.bean.IdRefTestBean" p:id-ref="bean1"/>
    13 </beans>

      。xmlns:p="http://www.springframework.org/schema/p": 首先指定命名空间;

      。<bean id="" class="" p:id=""/>:常量setter注入方式,等价于<property name="" value=""/>。

         。<bean id="" class="" p:id-ref=""/>:引用setter注入方式,等价于<property name="" ref=""/>。

      

      3.9 循环依赖

        循环依赖就是循环引用,就是两个或多个bean之间相互持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC又引用CircleA,则他们始终反应为一个环。

        构造器循环依赖:表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreateException。

    1 <bean id="circleA" class="cn.javass.spring.chapter3.bean.CircleA">
    2   <constructor-arg index="0" ref="circleB"/>
    3 </bean>
    4 <bean id="circleB" class="cn.javass.spring.chapter3.bean.CircleB">
    5   <constructor-arg index="0" ref="circleC"/>
    6 </bean>
    7 <bean id="circleC" class="cn.javass.spring.chapter3.bean.CircleC">
    8   <constructor-arg index="0" ref="circleA"/>
    9 </bean>
     1 @Test(expected = BeanCurrentlyInCreationException.class)
     2 public void testCircleByConstructor() throws Throwable {
     3 try {
     4  new ClassPathXmlApplicationContext("chapter3/circleInjectByConstructor.xml");
     5  }
     6  catch (Exception e) {
     7  //因为要在创建circle3时抛出;
     8  Throwable e1 = e.getCause().getCause().getCause();
     9  throw e1;
    10  }
    11 }

        setter循环依赖:表示通过setter注入方式构成的循环依赖,对于setter注入构成的循环依赖是通过spring容器提供的通过提前暴露刚完成构造器注入但还未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean的循环依赖。

     1 <!-- 定义 Bean 配置文件,注意 scope 都是“prototype”-->
     2 <bean id="circleA" class="cn.javass.spring.chapter3.bean.CircleA" scope="prototype">
     3    <property name="circleB" ref="circleB"/>
     4  </bean>
     5  <bean id="circleB" class="cn.javass.spring.chapter3.bean.CircleB" scope="prototype">
     6    <property name="circleC" ref="circleC"/>
     7  </bean>
     8  <bean id="circleC" class="cn.javass.spring.chapter3.bean.CircleC" scope="prototype">
     9    <property name="circleA" ref="circleA"/>
    10  </bean>
     1 //测试代码cn.javass.spring.chapter3.CircleTest
     2 @Test(expected = BeanCurrentlyInCreationException.class)
     3 public void testCircleBySetterAndPrototype () throws Throwable {
     4  try {
     5  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
     6 "chapter3/circleInjectBySetterAndPrototype.xml");
     7  System.out.println(ctx.getBean("circleA"));
     8  }
     9  catch (Exception e) {
    10  Throwable e1 = e.getCause().getCause().getCause();
    11  throw e1;
    12  }
    13 }

      对于prototype作用域bean,spring容器无法完成依赖注入,因为prototype作用域的bean,spring容器不进行缓存,因此无法提前暴露一个创建中的bean。对于singleton作用域的bean可以禁用循环引用 。

      

  • 相关阅读:
    linux NFS 的安装准备
    linux Sersync 参数说明
    linux测试 Sersync 是否正常
    linux开启 Sersync 守护进程进行数据同步
    linux 配置 Sersync
    Sersync 上配置 Sersync 服务
    linux Sersync 上配置客户端
    PowerDesigner一些小技巧
    C# System.Attribute(验证类)
    C#:实体类中做数据验证
  • 原文地址:https://www.cnblogs.com/ouhouki/p/9693341.html
Copyright © 2020-2023  润新知