互联网技术IT交流圈

Spring框架构造器/属性值/自动装配bean注入

2019-01-09  本文已影响4人  Java成长记_Camel

首先设置一个接口Performer.java表示参赛者。

package com.forework;
/**
 * 
 * 参赛者的接口
 * @author Administrator
 *
 */
public interface Performer {
    public void perform();
}

2.接口的实现类

package com.forework;
/**
 * 
 * 参赛者的接口
 * @author Administrator
 *
 */
public interface Performer {
    public void perform();
}

3.配置杂技师Poem.java 唱歌接口

package com.forework;

public interface Poem {
public  void recite();
}

4.配置唱歌的实现类

package com.forework;
/**
 * 唱歌
 * @author Administrator
 *
 */
public class Sonnet implements Poem{

    private static String[] LINES = {
            "When, in disgrace with fortune and men's eyes,",
            "I all alone beweep my outcast state,",
            "And trouble deaf heaven with my bootless cries,",
            "And look upon myself, and curse my fate,",
            "Wishing me like to one more rich in hope,",
            "Featur'd like him, like him with friends possess'd,",
            "Desiring this man's art and that man's scope,",
            "With what I most enjoy contented least;",
            "Yet in these thoughts myself almost despising,",
            "Haply I think on thee, and then my state,",
            "Like to the lark at break of day arising",
            "From sullen earth, sings hymns at heaven's gate;",
            "For thy sweet love remember'd such wealth brings",
            "That then I scorn to change my state with kings.",
    };
public  Sonnet(){
    

}

public void recite() {
     for (String line : LINES) 
         System.out.println(line);
    
}
}

5.配置会朗诵诗歌的杂技师ProjectJuggler.java

package com.forework;
/**
 * 会朗诵诗歌的杂技师
 * 
 * @author Administrator
 *
 */
public class ProjectJuggler extends Juggler {
    private Poem poem;    
    public ProjectJuggler(Poem poem) {        
        super();        
        this.poem = poem;
            }  
    //构造器的重载
    public  ProjectJuggler(int beanBags,Poem poem) {        
        super(beanBags);        
        this.poem = poem;
            }    
    public void perform(){
        super.perform();
        System.out.println("111111");
        poem.recite();
        
    }
}

理解:首先定义了一个接口Performer,然后写了一个类Juggler继承自Peformer,Juggler有一个私有成员变量beanBags,他的默认值是3,然后Juggler实现了Performer的perform方法,方法的输出带有beanBags的数量。
然后在测试的程序中,通过ApplicationContext类型对象加载了spring-idol.xml文件的内容,而在xml文件中定义了名为"duke"的bean,然后刚好就用到了。
然后bean返回的是一个Juggler

然后配置核心依赖注入文件ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--            定义一下接口的实现类依赖注入   id 随便起个名-->
<bean id="duke" class="com.forework.Juggler">
<!--构造器注入  name填写 要传的参数名  value传实参  替换nt beanBags = 3;  -->
<constructor-arg name="beanBags" value="15">

</constructor-arg>
</bean>

<bean id="sonnet" class="com.forework.Sonnet"/>
<bean id="poetic" class="com.forework.ProjectJuggler">
<!-- 其中有两个参数   -->
<constructor-arg value="10"></constructor-arg>
<!-- 第二个   引用型的参数   ref -->

<constructor-arg ref="sonnet"></constructor-arg>

</bean>
    
</beans>

最后 TestBean.java 测试类

package com.foreknow.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.forework.Performer;

public class TestBean {

    public static void main(String[] args) {
        //获取applicationContext.xml 配置bean 文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //指向这个ID 的实现类的对象
//        Performer performer = (Performer) context.getBean("duke");
        Performer performer1 = (Performer) context.getBean("poetic");
        
//        performer.perform();
        performer1.perform();
    }
}


显示结果:

image.png

注入各种bean属性

这里通过一个MoonlightPoet类来演示了注入Bean属性property的效果。

package com.forework;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MoonlightPoet {
    private String name;
    private int age;
    private Poem poem;
    private List<String> list;
    private Map<String, String> map;

    public void perform() {
        System.out.println("name : " + name);
        System.out.println("age : " + age);
        poem.recite();
        for (String val : list) 
            System.out.println("in list : " + val);
        for (Entry<String, String> entry : map.entrySet())
            System.out.println("in map : " + entry.getKey() + " -- " + entry.getValue());
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Poem getPoem() {
        return poem;
    }
    public void setPoem(Poem poem) {
        this.poem = poem;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public Map<String, String> getMap() {
        return map;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MoonlightPoet moonlightPoet = (MoonlightPoet) context.getBean("moonlightPoet");
        moonlightPoet.perform();
    }
}



配置核心依赖注入文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--            定义一下接口的实现类依赖注入   id 随便起个名-->
<bean id="duke" class="com.forework.Juggler">
<!--构造器注入  name填写 要传的参数名  value传实参  替换nt beanBags = 3;  -->
<constructor-arg name="beanBags" value="15">

</constructor-arg>
</bean>

<bean id="sonnet" class="com.forework.Sonnet"/>
<bean id="poetic" class="com.forework.ProjectJuggler">
<!-- 其中有两个参数   -->
<constructor-arg value="10"></constructor-arg>
<!-- 第二个   引用型的参数   ref -->

<constructor-arg ref="sonnet"></constructor-arg>

</bean>
<!-- 属性注入  -->
<bean id="moonlightPoet" class="com.forework.MoonlightPoet">
    <property name="name" value="moonlit" />
    <property name="age" value="22" />
    <property name="poem" ref="sonnet" />
    <property name="list">
      <list>
        <value>hello</value>
        <value>world</value>
        <!-- if bean, use <ref bean="XX"> -->
      </list>
    </property>
    <property name="map">
      <map>
        <entry key="key1" value="value1" />
        <entry key="key2" value="value2" />
        <entry key="key3" value="value3" />
      </map>
    </property>
</bean>


    
</beans>

输出结果:

image.png

理解:
注入简单值:
<property name="XX" value="YY" />
其中XX是变量名,YY是值。
引用其他Bean:
<property name="XX" ref="YY">
其中XX是变量名,YY是引用的bean的id。
装配List:
<property name="XX">
<value>YY</value>
或者
<ref bean="ZZ">
</property>
其中XX是变量名,YY是值,ZZ是引用的bean。
装配Map:
<map>
<entry key="XX" value="YY" />
或者
<entry key="XX" value-ref="YY" />
或者
<entry key-ref="XX" value="YY" />
或者
<entry key-ref="XX" value-ref="YY" />
</map>
因为map的key和value可以对应一个基础类型的值,也可以对应一个bean,所以key,value对应值,key-ref,value-ref对应bean。

自动装配bean

Spring提供了四种类型的自动装配策略:
byName – 把与Bean的属性具有相同名字(或者ID)的其他Bean自动装配到Bean的对应属性中。(ID的名必须与接口名对应)
byType – 把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中。(ID可以起任意的名字)
constructor – 把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean的对应属性中。
autodetect – 首先使用costructor进行自动装配。如果失败,再尝试使用byType进行自动装配。
这里以关羽和青龙偃月刀为例: 首先定义一个武器接口Weapon:

package com.moonlit.myspring;

public interface Weapon {    
    public void attack();
}

然后定义一个Weapon接口的实现Falchion类:

package com.moonlit.myspring;

public class Falchion implements Weapon {    
public void attack() {
        System.out.println("falcon is attacking!");
    }
}

定义一个英雄接口Hero:

package com.moonlit.myspring;

public interface Hero {    
    public void perform();
}

然后定义一个Hero接口的实现Guanyu类(代表关羽):

package com.moonlit.myspring;

public class GuanYu implements Hero {    

    private Weapon weapon;    
    public void perform() {
        System.out.println("GuanYu pick up his weapon.");
        weapon.attack();
    }    
    public Weapon getWeapon() {        

        return weapon;
    }    

    public void setWeapon(Weapon weapon) {        

        this.weapon = weapon;
    }
}

在不涉及自动装配的情况下,想要通过Spring的DI将Fachion类对象注入到Guanyu类的weapon属性中,可以新建一个xml文件(这里取名为spring-idol.xml)并在里面填写:

spring-idol.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <bean id="falchion" class="com.moonlit.myspring.Falchion" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu">
    <property name="weapon" ref="falchion" />
  </bean>
    </beans>

其中最主要的内容就是两个bean的声明部分:

<bean id="falchion" class="com.moonlit.myspring.Falchion" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu">
    <property name="weapon" ref="falchion" />
  </bean>

第一个bean标签定义了一个Falchion类型的bean,第二个bean标签中将第一个bean作为weapon的值装配到了weapon属性中。 然后可以写一个测试程序来查看效果:

package com.moonlit.practice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.moonlit.myspring.Hero;

public class AutowirePractice {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-idol.xml");
        Hero guanyu = (Hero) context.getBean("guanyu");
        guanyu.perform();
    }
}


输出结果如下:
GuanYu pick up his weapon.
falcon is attacking!

到目前为止还没有涉及到自动装配的内容,接下来开始讲述自动装配的内容。
byName自动装配
改变spring-idol.xml中bean声明内容的形式如下:

  <bean id="weapon" class="com.moonlit.myspring.Falchion" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byName" />

得到一样的结果。
将Falchion类的id去了一个和Guanyu类的属性weapon一样的名字,并且在guanyu bean中添加了autowire="byName"用于指明装配类型是byName自动装配。这个时候guanyu bean就是在上下文中找名为weapon的bean装配到他自己的weapon属性中。
byType自动装配

改变spring-idol.xml中bean声明内容的形式如下:

  <bean id="falchion" class="com.moonlit.myspring.Falchion" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

得到一样的结果。
这里已经不用关注Falchion类对应的bean的id是什么了,因为已经定义guanyu bean的autowire属性为"byType"。这个时候guanyu bean会在上下文中寻找和weapon具有相同类型的类对应的bean。
因为Guanyu类的weapon实现Weapon借口,整个上下文中目前只有一个Weapon接口的实现Falchion类,所以以"byType"类型就检测到了falchion bean并将其注入到了guanyu bean的weapon属性中。

但是也会出现一种情况就是检测的时候可能会出现多个相同type的bean,这个时候就不知道要装配那个了。比如,在新建一个实现Weapon接口的方天画戟类HalBerd:

package com.moonlit.myspring;

public class Halberd implements Weapon {    

    public void attack() {
        System.out.println("halberd is attacking!!!");
    }
}

并且在xml文件中声明一个新的halberd bean:

<bean id="halberd" class="com.moonlit.myspring.Halberd" />

在这种情况下就会出错,因为有两个bean满足byType的结果。
这个时候有两种解决办法:
第一种方法是将其中一个bean的primary属性设为false,比如:将方天画戟falchion bean的primary属性设为true,以防冠以使用方天画戟(很好奇吕布死了之后,赤兔马归关羽了,方天画戟去哪里了):

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
  <bean id="halberd" class="com.moonlit.myspring.Halberd" primary="true" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

输出结果如下:

GuanYu pick up his weapon.
halberd is attacking!!!

从输出结果中可以看到,关羽没有使用青龙偃月刀,而是使用方天画戟进行攻击了。
primary的默认属性是false。
第二种方法是设置其中一个bean的autowire-candidate属性为false,比如:将方天画戟的autowire-candidate属性设为false:

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
  <bean id="halberd" class="com.moonlit.myspring.Halberd" primary="true" autowire-candidate="false" />
  <bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

这个时候测试程序的输出如下:

GuanYu pick up his weapon.
falcon is attacking!

可以看到这个时候关羽又重拾了青龙偃月刀。可以看到,当halberd bean的autowire-candidate属性设为false时,他将不会作为自动装配的竞选bean之一,这个时候虽然halberd的primary属性为true,但是halberd bean没有参与自动装配的竞选,所以自动装配到了falchion。
这种感觉就好像:“隔壁村李小花觊觎已久,但是一个要成为海贼王的男人,于是拒绝了她……最终她嫁给了隔壁老王,过上了幸福的生活”。

上一篇下一篇

猜你喜欢

热点阅读