zoukankan      html  css  js  c++  java
  • Spring系列.依赖注入配置

    依赖注入的配置

    Spring的依赖注入分为

    • 基于构造函数的依赖注入
    • 基于setter方法的依赖注入

    基于构造函数的依赖注入

    <!-- 通过构造器参数索引方式依赖注入 -->
    <bean id="byIndex" class="cn.javass.spring.chapter3.HelloImpl3">
    	<constructor-arg index="0" value="Hello World!"/>
    	<constructor-arg index="1" value="1"/>
    </bean>
    <!-- 通过构造器参数类型方式依赖注入 -->
    <bean id="byType" class="cn.javass.spring.chapter3.HelloImpl3">
    	<constructor-arg type="java.lang.String" value="Hello World!"/>
    	<constructor-arg type="int" value="2"/>
    </bean>
    <!-- 通过构造器参数名称方式依赖注入 -->
    <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3">
    	<constructor-arg name="message" value="Hello World!"/>
    	<constructor-arg name="index" value="3"/>
    </bean>
    <!-- 通过静态的工厂方法注入 -->
    <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3" factory-method="getBean">
    	<constructor-arg name="message" value="Hello World!"/>
    	<constructor-arg name="index" value="3"/>
    </bean>
    

    基于setter方法的依赖注入

    <bean class="...HelloImpl4">
          <property name="message" value="Hello"/>
          <property name="index" value="1"/>  //value中的值全部是字符串形式,如果转换出错会报异常
    </bean>
    <bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2">
          <property name="msg" ref="message"/>  //msg属性是一个类对象
    </bean>
    

    循环依赖:创建Bean A需要Bean B,创建Bean B需要Bean C,创建Bean C需要Bean A 这样就形成了循环依赖。 Spring的解决方案:Spring创建Bean的时候会维护一个池,在创建A的时候会去池中查找A是否在池子中,假如发现就抛出循环依赖异常。

    避免依赖注入时的循环依赖:可以使用setter方式注入,不要使用构造器形式的注入。

    依赖配置常见列子

    常量值注入配置

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    	<!-- results in a setDriverClassName(String) call -->
    	<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    	<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
    	<property name="username" value="root"/>
    	<property name="password" value="masterkaoli"/>
    </bean>   
    

    注入其他Bean

    这边分别给出了一个引用当前容器和引用父容器中Bean的列子。

       <bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2">
    	<property name="msg">        //msg属性是一个类对象
                <ref  bean="message"/>   //引用同一个容器中id="message"的Bean
           </property>
       </bean>
        
        <!-- 引用父容器中的Bean -->
        <!-- in the parent context -->
        <bean id="accountService" class="com.something.SimpleAccountService">
        <!-- insert dependencies as required as here -->
        </bean>
     
        <!-- in the child (descendant) context -->
        <bean id="accountService" <!-- bean name is the same as the parent bean -->
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
            <ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
        </property>
        <!-- insert other configuration and dependencies as required here -->
        </bean>
    

    注入内部Bean

    内部bean:这种bean一般只让某个外部bean使用(和内部类相似),不让容器中的其他Bean使用。

        <bean id="outer" class="...">
            <property name="target">
                 <!-- this is the inner bean -->
                <bean class="com.example.Person"> 
                    <property name="name" value="Fiona Apple"/>
                    <property name="age" value="25"/>
                </bean>
            </property>
       </bean>
    

    集合的注入

    集合类的注入建议使用util命名空间

        <util:map id="myMap" key-type="java.lang.String" value-type="java.lang.String">
            <entry key="key1" value="chen"/>
            <entry key="key2" value="zhao"/>
        </util:map>
    
        <util:list id="myList" value-type="java.lang.String">
            <value>chen</value>
            <value>zhao</value>
        </util:list>
        
        <util:set id="mySet" value-type="java.lang.String" scope="singleton">
            <value>chen</value>
            <value>zhao</value>
        </util:set>
        
        <util:properties id="myProp" location="classpath:xx.properties"/>
    

    null值和空字符串的注入

       <bean class="...HelloImpl4">
            <property name="message"><null/></property> //null值
            <property name="index" value=""/>  //空字符串
      </bean>
    

    使用depends-on属性

    depends-on属性用来指定bean的初始化顺序。这个属性只对scope是单列的bean生效

        <!--在实例化beanOne之前先实例化manager和accountDao这两个bean-->
        <bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    	<property name="manager" ref="manager" />
        </bean>
        <bean id="manager" class="ManagerBean" />
        <bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
    

    懒加载

    bean的定义中有一个lazy-init这个属性,用来设置单列bean在容器初始化后是否实例化这个bean。默认情况下容器是会实例化所有单例bean的,我们也建议这么做,因为这样能在容器初始化阶段就发现bean配置是否正确。如果一个Bean按照下面的设置,lazy-init被设置为true那么它不会被容器预初始化,只有在被使用的时候才被初始化。但是如果有一个单列类依赖了这个Bean,那么这个被设置成懒加载的Bean还是会被预初始化。

       <bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
    

    如果想设置全局的单例Bean都不要预先初始化,那么可以在xml中做如下设置:

        <beans default-lazy-init="true">
            <!-- no beans will be pre-instantiated... -->
        </beans>
    

    Autowiring相关

    当我们要往一个bean的某个属性里注入另外一个bean,我们会使用property +ref标签的形式。但是对于大型项目,假设有一个bean A被多个bean引用注入,如果A的id因为某种原因修改了,那么所有引用了A的bean的ref标签内容都得修改,这时候如果使用autowire="byType",那么引用了A的bean就完全不用修改了。

     <!--autowire的用法如下,对某个Bean配置autowire模式 -->
     <!--和给Bean的属性添加@AutoWired注解的效果一致-->
     <bean id="auto" class="example.autoBean" autowire="byType"/>
    

    autowire的几种模式:

    • no模式:也是默认模式,这种模式下不会进行自动属性注入,需要我们自己通过value或者ref属性进行配置;
    • byName模式:通过属性的名称自动装配,Spring会在容器中查找名称与bean属性名称一致的bean,并自动注入到bean属性中。当然bean的属性需要有setter方法。例如:bean A有个属性master,master的setter方法就是setMaster,A设置了autowire="byName",那么Spring就会在容器中查找名为master的bean通过setMaster方法注入到A中;
    • byType:通过类型自动装配(注入)。Spring会在容器中查找类(Class)与bean属性类一致的bean,并自动注入到bean属性中,如果容器中包含多个这个类型的bean,Spring将抛出异常。如果没有找到这个类型的bean,那么注入动作将不会执行;
    • constructor:类似于byType,但是是通过构造函数的参数类型来匹配。假设bean A有构造函数A(B b, C c),那么Spring会在容器中查找类型为B和C的bean通过构造函数A(B b, C c)注入到A中。与byType一样,如果存在多个bean类型为B或者C,则会抛出异常。但时与byType不同的是,如果在容器中找不到匹配的类的bean,将抛出异常,因为Spring无法调用构造函数实例化这个bean;
    • default : 采用父级标签(即beans标签的default-autowire属性)的配置。

    需要注意的是上面这5中方式注入都需要我们提供相应的setter方法,通过@Autowired的方式不需要提供相应的setter方法。

    自动装配的缺点

    • 属性和构造函数参数设置中的显式依赖项会覆盖自动装配;

    将Bean排除自动装配

    如果按照下面的方式配置了Bean,那么这个Bean将不会作为自动装配的候选Bean。但是autowire-candidate自会对byType形式的自动注入生效,如果我们是通过byName的形式进行自动注入,那么还是能注入这个Bean。

        <bean id="auto" class="example.autoBean" autowire="byType" autowire-candidate="false"/>
    

    如果我们只想让某些Bean作为自动装配的候选Bean,那么可以进行全局设置。如果做了下面的配置,那么只有id为bean1和bean2的Bean才会成为自动装配的候选Bean。同时default-autowire-candidates的值支持正则表达式形式。但是强烈建议不要配置这个选项的值,使用默认的配置就行。

        <beans default-autowire-candidates="bean1,bean2">
        </beans>
    

    方法注入(单例依赖原型Bean)

    我们在配置bean的时候首先要考虑这个bean是要配置成单例模式还是其他模式。 在我们的应用中,绝大多数类都是单例类。当单例类引用单例类,或者原型类引用原型类、单例类时,我们只要像普通的配置方式就行了。但是当一个单例类引用原型类时,就会出现问题。这种情况可以使用下面的方式进行注入。

    @Service
    @Scope("prototype")
    public class MyService1 {
        public void service() {
           System.out.println(this.toString() + ":id");
        }
    }
    	
    @Service
    public abstract class MyService {
    
        private MyService1 service1;
        public void useService(){
         service1 = createService1();
         service1.service();
        }
    
        @Lookup("myService1")
        public abstract MyService1 createService1();
    
    }
    	
    //也可以这样配置bean
    <bean id="serviceC" class="com.csx.demo.springdemo.service.ServiceC">
        <lookup-method bean="serviceD" name="createService"/>
    </bean>
    <bean id="serviceD" class="com.csx.demo.springdemo.service.ServiceD"     scope="prototype"/>
    
  • 相关阅读:
    Q/GDW 10233-2018等国家电网公司电动汽车充电设备相关标准
    TB/T 2628-2020 铁路预制普通钢筋混凝土简支梁
    GB/T 51396-2019 槽式太阳能光热发电站设计标准
    GB/T 17467-2020 高压/低压预装式变电站
    GB/T 3906-2020 3.6 kV~40.5 kV交流金属封闭开关设备和控制设备
    GB 51388-2020 镍冶炼厂工艺设计标准
    GB/T 51409-2020 数据中心综合监控系统工程技术标准
    linux-09(查看文件命令tail)
    jmeter-02
    2019-3-19记随手记面试
  • 原文地址:https://www.cnblogs.com/54chensongxia/p/13065434.html
Copyright © 2011-2022 走看看