一、spring的作用域分五种:
1.singleton: bean的默认作用域,spring容器内存在一个实例。(用这个作用域有一个缺点待补)。
2.prototype:一次调用,产生一次实例。原话是every be requested。
3.reuqest:针对于http,一次请求一个实例。
3.session:针对于http,同一个session一个实例。原话是 each HTTP session by the web container.
4.globalSession:原话 beans for Portlet applications.单点登录。理解上,跨域session同一实例。
二、当前遇到的需求,一个方法,入参和返回值格式比较固定,但是内容涉及计算等,相对复杂,所以要做成模版式。每次调用这个方法都返回一个新的实例,想过用ThreadLocal,模拟spring jdbcTemplate,但是存在一个问题,一个方法,如果内部不单独起线程,那么就是一个线程,我可能会在方法内部调用n(n>=1)次方法,所以ThreadLocal不可取。利用spring bean's prototype scope 可以达到我想要的目的(每次调用都会产生一个实例)。
三、模拟模版类,将模版类简化为,里面有一个共享变量(非 volatile),一个方法,然后将当前对象注入spring容器中。如下:
bean的生成周期大家都知道,我没有给init-method 而直接做一个无参构造函数代替。
我要做的实验就是,在另一个类中注入此bean,然后连续调用say方法,看bean是否实例化指定次数,共享变量是否依次增加。
如上图,是测试类,当前项目基于springboot。测试结果如下
并没有得到我们想要的结果。实例化两次依据日志个人分析:第一次注解@Service将当前类注入到bean中,当然如果你指定lazy的话应该不会加载。第二次,@Autowired 注入。因为我在方法内部第一行打的断点。有好友说,是@Autowired的问题,应该每调一次方法 就@Autowired一次,我试过了不行,原理应该是,当前bean已经交给spring管理,所以,多少次注入结果都是一样的。
找原因:个人直觉,定位到@Scope注解,源码如下:
属性中value和scopeName是一样的,由@AliasFor得知。ConfigurableBeanFactory.SCOPE_PROTOTYPE="prototype"所以我上面没写错。那看最后一个属性proxyMode,指定代理类型。还有
红色区域内,不会产生代理除非定义的类型不同与default。
看看ScopedProxyMode里都有什么?如下:
原来default=no,而interfaces为接口代理,也就是jdk代理,target_class为类代理。
恍然大明白,修改自己的代码如下:
运行:
结果:perfect!
分享一个坑,也有解决问题的思路。
如果哪里有误,或者有其他建议,不用保留!!!
网友评论