spring boot 使用Scope详解
1.spring Bean 的作用域 singleton:在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。 prototype :每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。 request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。 session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。
2.使用web 作用域的启动报错解决方法 主要讨论一下上面的四种作用域,我这有个业务场景就是有一个记录日志的工具类里面有属性列表元素,每个调用的地方都会操作这个属性,所以用singleton会有线程安全,改用prototype发现还是会有线程安全问题。因为注入的工具类这个对象属于这个类的,被注入类所有的接口共享这个对象。
@Slf4j @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //@Scope(value = WebApplicationContext.SCOPE_SESSION,proxyMode = ScopedProxyMode.TARGET_CLASS) public class LogUtil { private List<Object> oldBeanList = new ArrayList<>(); private List<Object> newBeanList = new ArrayList<>(); //用于验证是否是同一对象的属性 private double r = Math.random(); public void printR(){ System.out.println("随机数:" +r); } }
有两个Controller注入了这个类
@RestController public class TestController { @Autowired private LogUtil logUtil; @GetMapping("test") public String test(){ System.out.println(logUtil.hashCode()); logUtil.printR(); System.out.println("======================================="); return "测试"; } @GetMapping("test1") public String test1(){ System.out.println(logUtil.hashCode()); logUtil.printR(); System.out.println("======================================="); return "测试"; } }
@RestController public class TestOneController { @Autowired private LogUtil logUtil; @GetMapping("testOne") public String test(){ System.out.println(logUtil.hashCode()); logUtil.printR(); System.out.println("======================================="); return "测试"; } }
作用域为singleton不管访问哪个接口打印结果都一样,这个不用解释。 prototype,test和test1是一样的结果,访问tetsOne结果不同 request,test,test1和testOne的hashCode都一样,但printR打印数据不一样,重复访问一个接口printRd的数据会改变 session关闭浏览器再此打开访问,printR会变。 可以看出后两种是注入的是一个代理,只有真的使用时才去取真正的bean 所以后两种的hashCode不会变,printR会打印出不一样的数据
使用web的作用域(request,session) @Scope必须要指定proxyMode这个参数,不然启动会报错 INTERFACES:如果这里的LogUtil是接口就使用这个参数,这个会用jdk代理 TARGET_CLASS:如果注入的是类用这个参数,这里会用cglib代理。 说明:如果不知道jdk代理和cglib的区别可以百度。