zoukankan      html  css  js  c++  java
  • Spring之Bean的注入

    Bean的配置中介绍的是Bean声明问题,在哪声明怎么声明的问题。Bean的注入是怎么实例化,怎么注入的问题。Bean注入的方式有两种,一种是在XML中配置,另一种则是使用注解的方式注入。

    一、XML方式注入

    XML方式注入一般有三种方式:属性注入、构造函数注入和工厂方法注入。

    一、属性注入
    在传统的对象实例化时可以通过new class(),然后通过setXXX()方法设置对象的属性值或依赖对象,属性注入也是采用这种方式,只是Spring框架会在内部完成这些操作,它会先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。它会使用默认的构造函数(无参数构造函数),只需为注入的属性设置set方法,可选择性和灵活性比较高,所以也是比较常用的一种注入方式。这里示例还是在IOC章节使用人和空气的基础上稍作修改来演示。IAir接口和CleanAir、DirtyAir类不变,这里就不贴了。

    1.新建XMLInstance类

    package com.demo.model;
    
    public class XMLInstance {
        
        
        private String name;
        
        public void setName(String name) {
            this.name = name;
        }
        private IAir air;
        
        public void setAir(IAir air) {
            this.air = air;
        }
        public void Breath()
        {
            System.out.println("Name:"+this.name+";Air:"+this.air.toString());
        }
        
        public XMLInstance(String name, IAir air) {
            super();
            this.name = name;
            this.air = air;
        }
        public XMLInstance() {
            
        }
        public void DestoryMethod()
        {
            System.out.println("DestoryMethod");
        }
        public void InitMethod()
        {
            System.out.println("InitMethod");
        }
    }
    View Code

    在XMLInstance类中并未声明构造函数,对于air属性只设置了set方法,get方法也没设置。

      <bean id="CleanAir" class="com.demo.model.CleanAir">
            <qualifier value="cleanair"/> 
      </bean> 
      <bean id="xmlinstance" class="com.demo.model.XMLInstance">
          <property name="air" ref="CleanAir"></property>
          <property name="name" value="abc"></property>
      </bean>

    Xml中使用property类配置属性,name是属性名,value用来设置基本数据类型的属性值。Spring配置文件中bean之间可以相互引用,引用时可以用<ref>标签配置bean的id属性使用。<ref>可以用在<property>属性中,也可以用在<construct-arg>构造函数的参数值,还可以用在其他地方,通过引用能减少bean的声明。

    二、构造函数注入
    在属性注入时先使用默认的构造函数(无参数构造函数)实例化,然后通过set方法注入属性,在传统实例化对象时可以自定义构造函数进行实例化,构造函数注入就是通过自定义构造函数来进行对象的实例化。这里在XMLInstance类的基础上增加了一个构造函数,第一个参数是String类型的name,第二个参数是IAir类型的air。

        public XMLInstance(String name, IAir air) {
            super();
            this.name = name;
            this.air = air;
        }

    Xml中使用使用<construect-arg>来设置构造函数的参数,index属性设置参数的顺序,参数顺序应该与构造函数的一致,ref设置引用bean的id,value设置构造函数参数的值。

      <bean id="xmlcontructinstance" class="com.demo.model.XMLInstance">
          <constructor-arg index="1" ref="CleanAir"></constructor-arg>
          <constructor-arg index="0" value="abc"></constructor-arg>
      </bean>

    三、工厂方法注入
    工厂方法注入参考的是工厂设计模式,通过在工厂类中实现对象的实例化。工厂类负责创建一个或多个目标类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例,工厂类对外屏蔽了目标类的实例化步骤,调用者甚至不用知道具体的目标类是什么。工厂方法也分静态工厂方法和非静态工厂方法,静态工厂方式不用实例化工厂类,直接通过类名调用,非静态工厂方法需要先实例化工厂类,然后通过工厂类对象调用获取对象。这里创建了一个工厂类XMLFactory,在类中定义了一个静态方法,和一个实例方法用来实例化bean对象。

    package com.demo.model;
    
    public class XMLFactory {
        
        public XMLInstance CreateInstance()
        {
            return new XMLInstance("instance",new CleanAir());
        }
        
        public static XMLInstance CreateStaticInstance()
        {
            return new XMLInstance("static instance",new CleanAir());
        }
    }

    1.静态工厂方法
    只需设置工厂方法对应的类,以及对应的工厂方法。

    <bean id="xmlfactorystaticinstance" class="com.demo.model.XMLFactory" factory-method="CreateStaticInstance"></bean>

    2.实例工厂方法
    需要先实例化工厂类,再通过工厂类对象调用实例方法获取bean对象。

     <bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>

    四、常见数据类型注入

    (1)List属性注入
    使用<list>配置java.util.List类型的属性。List属性中元素可以是任何数据类型的值,如果是Java对象可以使用ref指定,或使用<bean>定义新实例。如果是基础数据类型可直接用字符串。<list>中的元素会按配置的先后顺序排序。

          <property name="lists">
             <list>
                <value>1</value>
                <ref bean="CleanAir" />
                 <bean class="com.demo.model.CleanAir"/>
            </list>
        </property>

    (2)Set属性注入
    使用<set>配置java.util.Set类型的属性。Set属性中元素可以是任何数据类型的值,如果是Java对象可以使用ref指定,或使用<bean>定义新实例。如果是基础数据类型可直接用字符串。<set>中的元素没有先后顺序。

          <property name="sets">
            <set>
                <value>1</value>
                <ref bean="CleanAir" />
                 <bean class="com.demo.model.CleanAir"/>
            </set>
        </property>

    (3)Map属性注入
    使用<map>配置java.util.Map类型的属性。<entry>配置Map里的元素,Key指定索引,value指定值。如果是Java对象可以使用ref指定,或使用<bean>定义新实例。

        <property name="maps">
            <map>
               <entry key="key1" value="1"></entry>
                <entry key="key2" value-ref="CleanAir"></entry>
                <entry key="key3" >
                     <bean class="com.demo.model.CleanAir"/>
                </entry>
            </map>
        </property>

    (4)Properties属性注入
    使用<props>配置java.util.Properties类型的属性。<props>配置一个Properties对象,<prop>配置一条属性,属性Key配置索引。

        <property name="pros">
            <props>
                <prop key="prokey1">prokeyA</prop>
                <prop key="prokey2">prokeyB</prop>
            </props>
        </property>

    (5)自定义属性编辑器

    对于有一些属性是没法注入的,此时就需要自定义,比如日期类型。可以通过继承PropertyEditorSupport的类,重写setAsText方法来实现注入。这里定义了CustomerProperty继承PropertyEditorSupport,重写了setAsText方法,并将该bean配置到xml中。

    package com.demo.model;
    
    import java.beans.PropertyEditorSupport;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    
    public class CustomerProperty extends PropertyEditorSupport {
        private String format="yyyy-MM-dd";
        public String getFormat() {
            return format;
        }
        public void setFormat(String format) {
            this.format = format;
        }
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            
            SimpleDateFormat sdf=new SimpleDateFormat(format);
            //super.setAsText(text);
            try {
                //转换对象,能过setValue方法重新赋值
                this.setValue(sdf.parse(text));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
     <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
         <property name="customEditors">
              <map>
                   <entry key="java.util.Date" value="com.demo.model.CustomerProperty"/>
               </map>
         </property>
    </bean>

    配置之后就可以注入Date类型的属性了。

        <property name="date" value="2018-8-20"/>

    这里新建了XmlCollectionsDemo类,配置了上面的几个类型的属性来演示。

    package com.demo.model;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class XmlCollectionsDemo {
        
        private List<Object> list;
        
        private Properties pros;
        
        private Set<Object> sets;
        
        private Map<String,Object> maps;
        
        private Date date;
        
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    
        public List<Object> list() {
            return list;
        }
    
        public void setLists(List<Object> list) {
            this.list = list;
        }
    
        public Properties getPros() {
            return pros;
        }
    
        public void setPros(Properties pros) {
            this.pros = pros;
        }
    
        public Set<Object> getSets() {
            return sets;
        }
    
        public void setSets(Set<Object> sets) {
            this.sets = sets;
        }
    
        public Map<String, Object> getMaps() {
            return maps;
        }
    
        public void setMaps(Map<String, Object> maps) {
            this.maps = maps;
        }
        
        public static void main( String[] args ) throws Exception
        {
    
            ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
            BeanFactory factory=context;
            XmlCollectionsDemo annontationInstance=(XmlCollectionsDemo)factory.getBean("xmlCollectionsDemo");
            System.out.println(annontationInstance.list);
            System.out.println(annontationInstance.pros);
            System.out.println(annontationInstance.sets);
            System.out.println(annontationInstance.maps);
            System.out.println(annontationInstance.date);
        }
    }
    View Code
      <bean id="xmlCollectionsDemo" class="com.demo.model.XmlCollectionsDemo">
          <property name="lists">
             <list>
                <value>1</value>
                <ref bean="CleanAir" />
                 <bean class="com.demo.model.CleanAir"/>
            </list>
        </property>
          <property name="sets">
            <set>
                <value>1</value>
                <ref bean="CleanAir" />
                 <bean class="com.demo.model.CleanAir"/>
            </set>
        </property>
        <property name="maps">
            <map>
               <entry key="key1" value="1"></entry>
                <entry key="key2" value-ref="CleanAir"></entry>
                <entry key="key3" >
                     <bean class="com.demo.model.CleanAir"/>
                </entry>
            </map>
        </property>
        <property name="pros">
            <props>
                <prop key="prokey1">prokeyA</prop>
                <prop key="prokey2">prokeyB</prop>
            </props>
        </property>
        <property name="date" value="2018-8-20"/>
      </bean>
    View Code

     通过运行main方法,打印出属性值。
    [1, CleanAir, CleanAir]
    {prokey2=prokeyB, prokey1=prokeyA}
    [1, CleanAir, CleanAir]
    {key1=1, key2=CleanAir, key3=CleanAir}
    Mon Aug 20 00:00:00 CST 2018

    五、初始化函数、销毁函数
    通过上面3种注入方式的学习也对通过xml对bean实例化有的了解,有的对象在实例化之后还需要执行某些初始化代码,但这些初始化代码还不能写在构造函数中,此时可以将初始化代码写到某个方法中,将init-method属性值设置为该方法,Spring会强制执行该方法进行初始化。而又的对象在使用完毕之后需要释放,可以使用destroy-method来进行销毁。

        public void DestoryMethod()
        {
            System.out.println("DestoryMethod");
        }
        public void InitMethod()
        {
            System.out.println("InitMethod");
        }

    这里先在XMLInstance类中增加了上面两个方法来模拟销毁和初始化方法。然后在xml配置bean时就可以设置destroy-method、init-method属性的值对应两个方法的方法名。注解中@PostConstruct对应init-method,@PreDestory对应destroy-method。

    <bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>

    二、注解注入方式

    一、常用注解介绍
    学习完XML注入之后再学习注解方式注入就容易的多,注解方式注入主要涉及到@Autowired,@Resource,@Required,@Qualifier,@Value这几个注解。在第2章节的2.2.4IOC实例中定义Person时就使用过@Autowired、@Qualifier。下面来了解下它们具体用法。
    @Autowired:默认是按类型匹配注入bean,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。在使用@Autowired时,首先在容器中查询对应类型的bean,如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据,如果查询的结果不止一个,那么@Autowired会根据名称来查找。如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false。
    @Required:适用于bean属性setter方法,并表示受影响的bean属性必须在XML配置文件在配置时进行填充。否则,容器会抛出一个BeanInitializationException异常。
    @Qualifier:@Autowired默认是单实例的,但是在面向接口编程中,如果把一个属性设置为接口类型,一个接口可能有多个实现,那到底是注入哪一个呢?为了解决这个问题,就有了@Qualifier。
    @Value:在xml配置属性时可以通过property的value设置默认值,@Value也可以为属性设置默认值。
    @Resource:默认按名称匹配注入bean。要求提供一个bean名称的属性,如果属性为空,则自动采用标注处的变量名或方法名作为bean的名称。如果我们没有在使用@Resource时指定bean的名字,同时Spring容器中又没有该名字的bean,这时候@Resource就会退化为@Autowired即按照类型注入。

    package com.demo.model;
    
    import javax.annotation.Resource;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Required;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class AnnontationInstance {
        
        @Value("abc")
        private String name;
        
        
        public void setName(String name) {
            this.name = name;
        }
        
        //@Resource与@Autowired两者选其一
        //    @Autowired
        //    @Qualifier(value="cleanair")
        private IAir air;
        @Resource(name="CleanAir")
        public void setAir(IAir air) {
            this.air = air;
        }
        
        public void Breath()
        {
            System.out.println("Name:"+this.name+";Air:"+this.air.toString());
        }
    }

    上面代码使用@Value注解为name设置了默认值,使用@Resources设置bean的名称为IAir属性注入bean,也可以使用@Autowired+@Qualifier为IAir注入bean。

    二、开启注解
    上面配置完注解之后,还要告诉Spring开启注解,这样@Autowired、@Resources这些注解才起作用。开启有两种比较简单的方式。
    1.在xml配置文件中使用context:annotation-config

      <context:annotation-config />

    2.在xml配置文件中使用context:component-scan

    <context:component-scan base-package="com.demo.model"/>
  • 相关阅读:
    (引)spring学习笔记1.什么是控制反转
    Arduino 各种模块篇 步进电机 step motor 舵机 servo 直流电机 总复习
    Raspberry Pi Wireless Adaptor
    Pyramid 使用总结1
    Arduino 各种模块篇 人体红外感应模块 proximity sensor
    Pyramid 使用总结2
    Webcam Streaming Desktop Recording on Linux for ubuntu or its destros
    Arduino 各种模块篇 步进电机 step motor( 不用库,不用shield, 纯)
    Arduino 各种模块篇 motor shield 电机扩展板(舵机、直流电机、步进电机party)
    转载 stepper motors
  • 原文地址:https://www.cnblogs.com/5ishare/p/9508805.html
Copyright © 2011-2022 走看看