什么是Bean的作用域呢?

这里的"作用域"还和Java中的类级,方法级等这几个作用域概念不太一样,我自己的一个理解是:在Spring执行的这段时间中,Bean的作用域就只有单例和多例这两种,在执行respect这段时间之中,就有它自己的作用域,而到了session中又有它自己的作用域,像类似的还有application和WebSocket作用域.

我们为什么要了解Bean的作用域呢?

我们在实际应用中,要根据Bean的用法来设置Bean的作用域,比如你和别人一起协同开发的代码中有个Bean不想别人改动,那就可以通过调整Bean的作用域来解决.

下面用一个案例还原案发过程(Spring中的请况):

张三有自己的可爱小猫对象

@Component
public class CatBeans {
    @Bean
    public Cat cat(){
        Cat cat = new Cat();
        cat.setName("莫妮卡");
        return cat;
    }
}
@Component
public class BeanScopes1 {
    @Autowired
    private Cat cat;
    //张三自己调用

    public Cat getCat() {
        return cat;
    }
}

李四看到了,也想要有自己的小猫,所以他用张三的小猫对象复刻了个自己的对象:

@Component
public class BeanScopes2 {
    @Autowired
    private Cat cat;

    //李四调用
    public Cat getCat() {
        Cat myCat = cat;//李四创建了自己的小猫Bean
        myCat.setName("myCat");//李四给自己的猫改了名
        return myCat;
    }
}

 然后他调用了:

 发现还挺可爱,简直跟张三的猫一样可爱.

当张三第二次调用自己的小猫的时候,发现自己的猫变了

 

 发现了他的猫不是莫妮卡了,而是被改成myCat,这时候李四也才知道,原来自己的小猫对象和张三的是同一个.

这是为什么呢,李四明明重新建立一个Cat对象啊.

其实真实的情况是Spring的IoC容器有两种作用域模式,一种是IoC默认的singleton(单例作用域),一种是可手动修改的prototype(原型作用域 / 多例作用域),在默认情况下,IoC容器采用singleton,也就是所有人获取到的都是同一个Bean对象,这样效率会高很多.

Spring中怎么修改作用域呢?

这个很简单,只要在想修改作用域的Bean对象那里加个@Scope注解,然后在注解后面加个小括号,小括号里面写上你想改成哪种作用域:(单例)"singleton"或者(多例)"prototype".例如:

@Component
public class CatBeans {
    @Scope("prototype")
    //@Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)
    //通过Spring内置定义的字符串设置属性也行
    @Bean
    public Cat cat(){
        Cat cat = new Cat();
        cat.setName("莫妮卡");
        return cat;
    }
}

 这样就能解决两个人只有一只猫的问题辣.

singleton和prototype这两种都是Spring中的Bean作用域

Spring官方对这两种作用域的描述大致是:

singleton: 在IoC容器中只有一份实例,获取Bean(指使用ApplicationContext.getBean()等方法获取)和装配Bean(即使用@Autowired注入),获取到的都是同一个对象.

场景:Spring中的默认选择

prototype: 每次对该作用域下的Bean的请求都会创建新的实例,获取Bean(指使用ApplicationContext.getBean()等方法获取)和装配Bean(即使用@Autowired注入),获取到的都是新的对象.

场景:通常有状态的Bean使用这个作用域.

还有四种是在Spring MVC中才生效的:

1.request(请求作用域): 一次http请求中会生成一个新的Bean实例类似于prototype

场景: 一次http的请求和响应共享Bean.

2.session(会话作用域): 在http session中定义一个Bean实例

场景: 在用户会话中共享Bean.例如:可以用来记录一个用户的登录信息

3.application(全局作用域): 在⼀个http servlet Context中,定义⼀个Bean实例

场景:Web应用的上下文信息.

4.websocket(HTTP WebSocket作用域): 在一个HTTP WebSocket生命周期中,定义一个Bean实例

场景:WebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第⼀
次初始化后,直到WebSocket结束都是同⼀个Bean.

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐