阿狸先森|为何设置@Scope("prototype")无效?
导读:本文将以一个设置Spring Beans scope为Prototype 但没有达到期望结果的例子 , 展开讨论其原因以及解决的方案 。
Singleton默认情况下 , bean是单例模式 。 也就是说其在 spring application context中只有一个实例 。
Prototype如果我们希望spring每次都创建一个新实例 。 我们可以将scope设置为prototype , 如下:
@Scope("prototype")//或者@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)复杂场景场景:类A作用域是Singleton单例 , 类B作用域是Prototype原型 。 类A依赖于类B(在类A中 , 我们需要使用类B的实例) 。
@Componentpublic class A {//依赖于B@AutowiredB b;public void doSomthing(){System.out.println(b);b.doSth();}}@Component@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public class B {public void doSth(){}}在这种情况下 , 如果我们调用类a中的一个方法 , 并且在这个方法中使用了类B的实例 。 我们会发现 , 即使我们声明了类B为prototype原型@Scope("prototype") , 但仍然只使用了类B的一个实例 。
出现该问题的原因Method Injection is useful in scenarios where you need to inject a smaller scope bean in a larger scope bean. For example, you have to inject a prototype bean inside an singleton bean , on each method invocation of Singleton bean. Just defining your bean prototype, does not create new instance each time a singleton bean is called because container creates a singleton bean only once, and thus only sets a prototype bean once.
大概意思是 , 当你把声明为相对范围小的作用域(例如:prototy)对象注入到相对范围大的作用域(例如:singleton)对象时 , 由于外层对象只会初始化一次 , 所以会导致内部注入的对象也只会被初始化一次 。
解决的方式要解决这个问题 , 我们需要使用代理(设置proxyMode) 。 通过这种方式 , 每次A调用B时 , 实际上是A在调用B的代理 , 代理将处理它(每次都创建新的实例) 。
@Component//设置proxyMode@Scope(value=http://kandian.youth.cn/index/ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = ScopedProxyMode.TARGET_CLASS)public class B {public void doSth(){......}}ScopedProxyMode.INTERFACES 和ScopedProxyMode.TARGET_CLASS 的区别?在区分ProxyMode之前 , 我们需要理解区分 JDK动态代理 及 CGLIB代理的概念 。 两者主要区别为:JDK的动态代理只能针对实现了接口的类生成代理 。 而cglib的动态代理是针对类实现代理 。
【阿狸先森|为何设置@Scope("prototype")无效?】ScopedProxyMode.INTERFACES(创建一个JDK动态代理)
//创建一个JDK动态代理@Scope(value = "http://kandian.youth.cn/index/prototype", proxyMode = ScopedProxyMode.TARGET_CLASS )理解:JDK动态代理是利用反射机制生成一个实现代理接口的匿名类 , 在调用具体方法前调用InvokeHandler来处理 。
public class Example {public static void main(String[] args) throws Exception {//被代理对象Foo target = new Foo();InvocationHandler proxyHandler = ... // some proxy specific logic, likely referencing the `target`// 反射机制Printable proxy = (Printable) Proxy.newProxyInstance(Example.class.getClassLoader(),target.getClass().getInterfaces(), proxyHandler);Foo foo = (Foo) proxy;}public static class Foo implements Printable {@Overridepublic void print() {}}public interface Printable {void print();}}
推荐阅读
- 检察日报|他为何掏空自己的公司 无锡市惠山区检察官揭开6000万元系列虚假诉讼之谜
- WBO|?新疆伊珠和烟台金沙岸葡萄酒添加甜蜜素被查!加“甜”为何屡禁不止?
- 吴磊|演员吴磊23万航空里程积分被粉丝盗刷,为何出现如此漏洞?
- 【】揭开国家草原自然公园的神秘面纱:为何建?怎么建?
- 央视新闻|大量死鱼、榴莲、猪蹄遍布海滩 粤桂海滩为何频现“另类海货”?
- 中国新闻网|服贸会观察:区块链为何能成全球贸易“助推器”?
- 【】服贸会观察:区块链为何能成全球贸易“助推器”?
- 中国天气网|又一个!“海神”携强风雨袭东北 为何台风最近总爱去东北?
- 晨株洲|炎陵为何赢得这么多投资商青睐,一天签约28个项目
- 央视新闻客户端|抗议活动持续超100天,美国这地“战火”为何愈演愈烈?
