Java Spring之Singleton bean与Prototype bean

Spring创建bean的时候默认是Singleton即单例模式,如果想要创建Prototype模式的需要在bean中设置scope


bean中的singleton模式

Spring在默认的情况下会将容器中的bean以单例模式初始化,这是什么意思呢?通过代码我们可以详细了解到
现在有这样三个类 Person PersonTwo Axe 具体内容如下
Person:

public class Person {
    private Axe axe;
    public Person(){
        System.out.print("初始化了person");
    }
    public void setAxe(Axe axe){
        this.axe = axe;
    }
    public void useAxe(){
        axe.chop();
    }
    public void setAxeChopString(String chopString){
        this.axe.setChopString(chopString);
    }
}

PersonTwo:

public class PersonTwo {
    private Axe axeTwo;

    public PersonTwo(){
        System.out.print("初始化了personTwo");
    }

    public void useAxe(){
        this.axeTwo.chop();
    }
    public void setAxeChopString(String chopString){
        this.axeTwo.setChopString(chopString);
    }

    public void setAxeTwo(Axe axeTwo) {
        this.axeTwo = axeTwo;
    }

//    public Axe getAxeTwo() {
//        return axeTwo;
//    }
}

Axe:

public class Axe implements AxeInterface{
    private String chopString;
    public void setChopString(String chopString){
        this.chopString = chopString;
    }
    public void chop(){
        System.out.print("\n"+this.chopString);
    }
}

bean的设置如下



    
        
    
    
        
    
    

在Person类中我们实现了默认构造方法,方法中打印了一些信息,我们可以先通过初始化两个Person类来看看打印信息打印了几次

public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

        if (ctx.containsBean("person")){
            Person a = (Person) ctx.getBean("person",Person.class);
            Person b  = (Person) ctx.getBean("person",Person.class);
    }
}

运行之后打印信息如下:

初始化了person

Person构造方法只走了一次,说明Person只被初始化了一次,不出意外的a与b指引的是相同的对象。实际上这一次初始化在ApplicationContext创建的时候就进行了具体见ApplicationContext的介绍可参考ApplicationContext

那么我们再来做个试验,将Axe作为bean的property同时赋值给Person和PersonTwo,然后在将Axe也加入到SpringContainer中

public class Application {
    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        if (ctx.containsBean("person")){
            Person a = (Person) ctx.getBean("person",Person.class);
            PersonTwo b  = (PersonTwo) ctx.getBean("personTwo",PersonTwo.class);
            a.setAxeChopString("去砍柴");
            a.useAxe();
            b.useAxe();
        }
    }
}

打印结果如下

初始化了person初始化了personTwo
去砍柴
去砍柴

Person和PersonTwo的初始化方法都被调用了,a与b调用useAxe方法的时候打印了相同的信息,实际上只有a才调用的setAxeChopString方法,证明了a与b指引的对象中的Axe属性赋值的对象是同一个对象,这样在以后的开发中我们就要注意到这种问题,单例机制固然可以起到重用节约资源的目的但在某些情况下确会导致异常情况就比如上面的代码更改一下我给b也调用setAxeChopString方法

public class Application {
    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        if (ctx.containsBean("person")){
            Person a = (Person) ctx.getBean("person",Person.class);
            PersonTwo b  = (PersonTwo) ctx.getBean("personTwo",PersonTwo.class);
            a.setAxeChopString("去砍柴");
            a.useAxe();
            b.setAxeChopString("去劈柴");
            b.useAxe();
            a.useAxe();
        }
    }
}

打印结果如下

初始化了person初始化了personTwo
去砍柴
去劈柴
去劈柴

我们明明想让a去砍柴,结果在b的作用下确变成了去劈柴,导致了异常,所以在写代码的时候一定要注意这个问题。

通常情况下我们只需要把bean设置成singleton就可以了,Spring也鼓励这么做,能够重用对象节约更多的资源。但是也要注意对象的引用问题,防止上述异常产生

使用ApplicationContext的时候会将容器中所有的singleton bean初始化,这就意味着在系统初期会产生大量的开销,如果想要避免这种开销可以给beans设置懒汉模式


或者单独设置bean的懒汉模式


你可能感兴趣的:(Java Spring之Singleton bean与Prototype bean)