• Bean的作用域



    默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。

    • 单例(Singleton): 在整个应用中,只创建bean的一个实例
    • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
    • 会话(Session):在Web应用中,为每个会话创建一个bean实例
    • 请求(Request):在Web应用中,为每个请求创建一个bean实例

    推荐使用方式

    @Component
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public class Notepad(.....)
    
    当然使用
    @Scope("prototype")也是可以的,但是推荐使用常量
    
    xml配置
    <bean id = "notepad" class = "com.lyc.Notepad" scope="prototype"/>

    使用会话和请求作用域

       在web应用中,single和prototype不太适合使用,相反 session和required的会比较合适。例如,在典型的电子商务应用中,可能会有一个bean代表用户的购物车。如果购物车是单例的话,那么将会导致所有的用户都会向同一个购物车中添加商品。另一方面,如果购物车是原型作用域(prototype),那么在应用中某一个地方往购物车中添加商品,在应用的另外一个地方可能就不可用了,因为在这里注入的是另外一个原型作用域的购物车。

          就购物车bean来说,会话作用域是最合适的,因为它与给定的用户关联性最大。要指定会话的作用域,我们可以使用@scope注解,它的使用方式与指定原型作用域是相同的

    @Component
    @Scope{value = WebApplicationContext.SCOPE_SESSION,proxyMode = ScopedProxyMode.INTERFACES}
    public  ShoppingCart Cart(){....}

      这里,我们将value设置为WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。这会告诉spring为web应用中的每个会话创建一个ShoppingCart。这会创建多个ShoppingCart bean实例,但是对于给定的会话只会创建一个实例,在当前会话操作中,这个bean实际上相当于单例

      注意: @Scope同时还有一个ProxyMode,他被设置成了ScopedProxyMode.INTERFACES.这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。

      假设我们要将ShoppingCart bean注入到单例StoreService bean 的setter方法中,如下所示:

    @Component
    public class StoreService{
    @Autowired
    public void setShoppingCart(ShoppingCart shoppingCart){
       this. shoppingCart = shoppingCart;
    }
    .......
    }

      因为StoreService是一个单例的bean,会在Spring应用上下文加载的时候创建。当它创建的时候,Spring会试图将ShoppingCart bean注入到setShoppingCart()方法中。但是ShoppingCart bean是会话作用域的,此时并不存在。直到某个用户进入系统,创建了会话之后,才会出现ShoppingCart实例。
      另外,系统中将会有多个ShoppingCart实例;每隔用户一个。我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中。我们希望的是当StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那一个。
      Spring并不会将实际的ShoppingCart bean注入到StoreService中,Spring会注入一个到ShoppingCart bean的代理,这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为它就是一个购物车。但是当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Scope {
        @AliasFor("scopeName")
        String value() default "";
    
        @AliasFor("value")
        String scopeName() default "";
    
        ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
    }
    //  ScopedProxyMode 是一个枚举类
     public enum ScopedProxyMode {
        DEFAULT,
        NO,
        INTERFACES,
        TARGET_CLASS;
    
        private ScopedProxyMode() {
        }
    }

      如果ShoppingCart是接口而不是类的话,proxyMode属性被设置成ScopeProxyMode.INTERFACES,表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean
      如果ShoppingCart是一个具体的类,那么ProxyMode属性就设置为ScopedProxyMode.TARGET_CLASS,用来表明要以生成目标类扩展的方法创建代理

  • 相关阅读:
    Altium Designer中各层的含义
    国外现在有哪些众筹网站呢?
    C# 代码 手工 配置 Log4Net 2种方法
    Windows 7 里进程管理器里面的各列是什么含义?主要是和内存有关的内存-专用工作集,内存-工作集,内存-提交大小???
    C# .Net 下 x86使用大内存的处理
    CV学习日志:CV开发之关联Gazebo/Webots/ROS2
    CV学习日志:CV开发之Windows10环境搭建
    CV学习日志:CV开发之Ubuntu2004和WLS2环境搭建
    ROS2学习日志:ROS2Cartgrapher使用与调试
    ROS2学习日志:QoS要点总结
  • 原文地址:https://www.cnblogs.com/zhuguangzhe/p/12673872.html
Copyright © 2020-2023  润新知