Spring之作用域

单例模式

  • @Scope默认是单例模式,即scope=“singleton”。

  • 单例模式肯定是线程不安全的,一般来说只有类的属性/全局变更会导致多线程问题,而方法内的局部变量不会有并发问题

  • Spring的Bean中的自定义的成员变量可以用threadlocal封装,变成线程安全的

  • Spring提供的template等类没有多线程的问题

prototype

  • prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的
    getBean()方法)都会产生一个新的bean实例,相当与一个new的操作

  • 使用@Autowired没有实现多个实例,即使使用@Scope(BeanDefinition.SCOPE_PROTOTYPE)将Bean声明为prototype:

    1.外层的类是singleton
    2.使用@Autowired注入
    这样的话仍然指挥一个实例,举例:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ClassB {

    private Integer num = Integer.valueOf(0); //全局变量

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }
}

使用@Autowired注入到ClassA中

/**
 * Created by ASUS on 2017/5/24.
 */
@Component
public class ClassA {
    @Autowired
    private ClassB classB;

    public Integer addNum(){
        classB.setNum(classB.getNum()+1);
        System.out.println(classB.getNum());
        return classB.getNum();
    }
}

通过Controller调用,用@Autowire将ClassA注入。

@RestController
public class Controller {

    @Autowired
    private ClassA classA;

    @RequestMapping("/")
    public String print(){
        return classA.addNum().toString();
    }
}

每一次访问都会导致num+1
ClassB并没有被多次实例化,ClassA本身是一个单例,单例只会实例化一次,这样其属性自然也就只会被实例化一次。

  • ** 解决方法**

直接在方法中声明局部变量

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ClassA {
   public Integer addNum(){
       //不使用@Autowired,直接在方法中声明
       ClassB classB = new ClassB();
       classB.setNum(classB.getNum()+1);
       System.out.println(classB.getNum());
       return classB.getNum();
   }

注意:

这样做的问题在于,如果ClassB中需要使用@Autowired,则这个@Autowired会失效。

比如想在ClassB中使用Spring管理的JdbcTemplate,就需要使用@Autowired。如果ClassB不是通过@Autowired实例化的,ClassB中的JdbcTemplate就会注入失败,导致NullPointerException。

使用ThreadLocal管理属性
还要一个方法实现和多实例“类似”的功能,即使用ThreadLocal来管理类中的属性。例如对于上面的例子:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ClassB {

    //使用ThreadLocal管理属性,每个线程都操作一个新的副本
    private static ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    public ThreadLocal<Integer> getIntegerThreadLocal() {
        return integerThreadLocal;
    }
}

在ClassB中就可以正常使用@Autowired进行注入。

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ClassA {

    @Autowired
    ClassB classB;

    public Integer addNum(){
        Integer integer = classB.getIntegerThreadLocal().get();
        integer++;
        return integer;
    }
}
  • request
    request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,

  • session

      session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
    
  • global session

      global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。
    

request,sessuib.gobal session 正常宰项目中很少使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值