[Spring实战系列] - No.2 Bean基本知识

    在这一篇文章中,我将会简单地介绍有关Bean的基础知识,这也是Spring实战这本书的第二章节的主要内容。我所使用的代码也是来自于Spring 实战这本书。

  主要内容:

        1.什么是Bean?我们如何使用Bean?

        2.Setter注入和构造注入

        3.Bean的一些属性:内部Bean

        4.Bean的装配和范围化

    1. 什么是Bean?我们如何使用Bean?

        在第一篇文章中,我们曾经提到过Bean。什么是Bean?Bean是一种对象,我们使用Spring容器来控制其生命周期,进行对象的创建和分发。(说白了就是你定义的或者相关的类)Spring提供了多种容器,并分为两种:BeanFactory 和 应用上下文。如果你有兴趣了解具体上述两种容器架构的区别,可以到该博客仔细研究一下,这里不做赘述。

        那么我们如何使用Bean呢?有以下方法:

 BeanFactory factory = new XmlBeanFactory(new FileSystemResource("C:/spring.xml"));
        MyBean myBean = (MyBean) factory.getBean("nihao");

如果你在intellij中输入上述代码,你可能会得到代码XmlBeanFactory过时的提示。那我们应该怎么办呢?

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        OneManBand oneManBand = (OneManBand) context.getBean("onemanband");
同时,ApplicationContext提供三种经常使用的实现方式;

1. ClassPathXmlApplicationContext : 从类路径中XML文件载入上下文定义信息。

2. FileSystemXmlApplicationContext : 从文件系统中XML文件载入上下文定义信息,所以需要完整路径。

3. XmlWebApplicationContext:从Web系统中Xml载入上下文定义信息。

2.Setter注入和构造注入

    Setter注入,顾名思义就是使用Bean中的属性设置器来注入对象中的属性,那么构造注入也就是利用含参构造函数来注入属性。Setter注入的行为可以理解为我们使用无参构造函数来构造对象,然后调用属性设置器注入对象。同理,构造注入的行为可以理解为,我们利用含参构造函数直接构造对象。下面我们来看一个例子:

    我们有一个类Juggler:

/**
 * Created by YanMing on 2017/2/20.
 */

import org.junit.Test;
public class Juggler implements Performer {
    private int beanBags;

    public Juggler(){}

    public void setBeanBags(int beanBags)
    {
        this.beanBags = beanBags;
    }

    public Juggler(int beanBags)
    {
        this.beanBags = beanBags;
    }

    public void perform() {
        System.out.println("my beanBags is " + this.beanBags);
    }
}
    我们分别在spring.xml中写入两种注入方式:

    1.Setter注入:

<bean id="duke" class="Juggler">
        <property name="beanBags" value="5"></property>
    </bean>
    2.构造注入:

    <bean id="duke" class="Juggler">
        <constructor-arg value="15"></constructor-arg>
    </bean>
    在intellij中编写测试示例:

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

/**
 * Created by YanMing on 2017/2/20.
 */


public class JugglerTest {
    @Test
    public void setBeanBags() throws Exception {

    }

    @Test
    public void perform() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Juggler juggler = (Juggler) context.getBean("duke");
        juggler.perform();
    }

}
    注:我在这里使用了junit4的jar包,有需要的朋友可以去百度上下载然后导入项目。为某个Bean编写测试可以点击类名,然后按住alt+enter,点击创建测试实例,然后就可以像上面一样测试啦。

    可以为Bean注入对象属性么?答案自然是:Yes!在这里我们添加一个Poem接口,让我们的Juggler可以吟诗!

/**
 * Created by YanMing on 2017/2/20.
 */
public interface Poem {
    void recite();
}

/**
 * Created by YanMing on 2017/2/20.
 */
public class Sonnet29 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..."
    };

    public Sonnet29(){}

    public void recite(){
        for(int i = 0 ; i < Lines.length;i++)
        {
            System.out.println(Lines[i]);
        }
    }
}

/**
 * Created by YanMing on 2017/2/20.
 */
public class PoeticJuggler extends Juggler {
    private Poem poem;

    public PoeticJuggler(Poem poem){
        super();
        this.poem = poem;
    }

    public PoeticJuggler(int beanBags,Poem poem){
        super(beanBags);
        this.poem = poem;
    }

    public void perform(){
        super.perform();
        System.out.print("While reciting");
        poem.recite();
    }

}

<bean id="sonnet29" class="Sonnet29"></bean>
 <bean id="duke" class="PoeticJuggler">
        <constructor-arg value="15"></constructor-arg>
        <constructor-arg ref="sonnet29"></constructor-arg>
</bean>

public class JugglerTest {
    @Test
    public void setBeanBags() throws Exception {

    }

    @Test
    public void perform() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Juggler juggler = (PoeticJuggler) context.getBean("duke");
        juggler.perform();
    }

}



    3.Bean的一些属性:内部Bean

    内部Bean看上去是一个非常高大上的东西,其实非常简单,只需要在我们的spring.xml中这样声明:

 <bean id="sonnet29" class="Sonnet29"></bean>
 <bean id="duke" class="PoeticJuggler">
        <constructor-arg value="15"></constructor-arg>
        <constructor-arg>
            <bean class="Sonnet29"></bean>
        </constructor-arg>
</bean>
    如果我们的属性不是单一属性,而是某些集合怎么办呢?在这里我们就用到了装配集合。我们来看一个例子

/**
 * Created by YanMing on 2017/2/20.
 */
public interface Instruments {
    void play();
}

/**
 * Created by YanMing on 2017/2/20.
 */
import java.util.Collection;
public class OneManBand implements Performer {

    private Collection<Instruments> instruments;
    public OneManBand(){

    }

    public void perform(){
        for(Instruments ins:instruments)
        {
            ins.play();
        }
    }

    public void setInstruments(Collection<Instruments> instruments){
        this.instruments = instruments;
    }
}

/**
 * Created by YanMing on 2017/2/20.
 */
public class Piano implements Instruments {
    public void play(){
        System.out.println("Piano playing");
    }
}


public class Guitar implements Instruments {
    public void play(){
        System.out.println("Guitar playing");
    }
}


public class Saxophone implements Instruments {
    public void play(){
        System.out.println("Saxophone playing");
    }
}

/**
 * Created by YanMing on 2017/2/20.
 */
public class OneManBandTest {

    @Test
    public void perform() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        OneManBand oneManBand = (OneManBand) context.getBean("onemanband");
        oneManBand.perform();

    }

    @Test
    public void setInstruments() throws Exception {


    }

}
<bean id="guitar" class="Guitar" scope="singleton"></bean>
    <bean id="piano" class="Piano" scope="singleton"></bean>
    <bean id="saxophone" class="Saxophone" scope="singleton"></bean>

    <bean id="onemanband" class="OneManBand">
        <property name="instruments">
            <set>
                <ref bean="guitar"></ref>
                <ref bean="piano"></ref>
                <ref bean="saxophone"></ref>
            </set>
        </property>
    </bean>
        运行结果:


       同时,set还可以根据需要换成list,map等。相关的用法在网上也随处可见,这里不再赘述。

     那么,如果一个属性是空值该怎么办呢?我们使用<null/>元素

<property name="somenull"><null/></property>

    4.Bean的装配和范围化:

    在前面,我们已经学会了如何使用<constructor-arg>或<property>来显式地装配Bean。但是在大型的应用中,显式地装配会产生大量的xml。所以我们在这里引入自动装配。


    四种自动装配类型:

    1. byName 试图在容器中寻找和需要自动装配的属性名相同的Bean 

    2. byType 试图在容器中寻找一个与最需要自动装配的属性类型相同的Bean

    3. constructor 试图在容器中寻找与需要自动装配的Bean的构造函数参数一致的一个或多个Bean

    4. autodetect 按照 constructor 和 byType的顺序装配

    使用方式:

 <bean id="sonnet29" class="Sonnet29" autowire="byName"></bean>
    接下来,我们就来着重讲一下Bean的范围化:在默认的时候,我们每次请求一个Bean,都会准确的得到一个 Bean实例,并且这个实例是唯一的。那么我们可以每次获得不同实例么?可以Bean中有五种范围化规则:

singleton,prototype,request,session和global-session。后三种均和HTTP有关,在这里我们不做解释,我们只解释前两种。

    如何才能分辨我们的Bean实例是否为同一个呢?最好的方法是使用对象的hashcode。我们重新创建一个Bean,注册到配置文件中,然后在say()函数中输出this.hashcode(),查看结果

/**
 * Created by YanMing on 2017/2/21.
 */
public class BeanScope {
    public void say(){
        System.out.println("my hashcode is " +  this.hashCode());
    }
}

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

import static org.junit.Assert.*;

/**
 * Created by YanMing on 2017/2/21.
 */
public class BeanScopeTest {
    @Test
    public void say() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        BeanScope beanScope1 = (BeanScope) context.getBean("beanscope");
        BeanScope beanScope2 = (BeanScope) context.getBean("beanscope");

        beanScope1.say();
        beanScope2.say();

    }

}

<bean id="beanscope" class="BeanScope" scope="prototype"></bean>

        运行结果:

            1.Singleton

  2.Prototype

        

Github源码下载点击这里





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值