我刚到Spring,正在研究 proxyMode=ScopedProxyMode.TARGET_CLASS
. 我编写了一个简单的项目,用singleton和prototype bean来测试这一点。但是当我打印对象时,它会打印一个新的原型bean示例。
public class SimplePrototypeBean {
private String name;
//getter setters.
}
单粒豆
public class SimpleBean {
@Autowired
SimplePrototypeBean prototypeBean;
public void setTextToPrototypeBean(String name) {
System.out.println("before set > " + prototypeBean);
prototypeBean.setText(name);
System.out.println("after set > " + prototypeBean);
}
public String getTextFromPrototypeBean() {
return prototypeBean.getText();
}
}
配置类。
@Configuration
public class AppConfig {
@Bean
SimpleBean getTheBean() {
return new SimpleBean();
}
@Bean
@Scope(value = "prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public SimplePrototypeBean getPrototypeBean(){
return new SimplePrototypeBean();
}
}
单元测试
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class SimpleConfigTest {
@Test
public void simpleTestAppConfig() {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.println("Bean " + beanName);
}
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
SimpleBean simpleBean2 = (SimpleBean) ctx.getBean("getTheBean");
simpleBean1.setTextToPrototypeBean("XXXX");
simpleBean2.setTextToPrototypeBean("YYYY");
System.out.println(simpleBean1.getTextFromPrototypeBean());
System.out.println(simpleBean2.getTextFromPrototypeBean());
System.out.println(simpleBean2.getPrototypeBean());
}
}
输出
Bean org.springframework.context.annotation.internalAutowiredAnnotationProcessor
Bean org.springframework.context.annotation.internalCommonAnnotationProcessor
Bean org.springframework.context.event.internalEventListenerProcessor
Bean org.springframework.context.event.internalEventListenerFactory
Bean appConfig
Bean getTheBean
Bean scopedTarget.getPrototypeBean
Bean getPrototypeBean
springCertification.com.DTO.SimpleBean@762ef0ea
springCertification.com.DTO.SimpleBean@762ef0ea
before set > springCertification.com.DTO.SimplePrototypeBean@2f465398
after set > springCertification.com.DTO.SimplePrototypeBean@610f7aa
before set > springCertification.com.DTO.SimplePrototypeBean@6a03bcb1
after set > springCertification.com.DTO.SimplePrototypeBean@21b2e768
null
null
springCertification.com.DTO.SimplePrototypeBean@17a7f733
请参阅上面的输出始终显示新示例,并且文本字段中的值为null。我只运行一次这个应用程序。所以我希望在调用simplebean1和simplebean2时只创建2个原型示例。有人能给我解释一下为什么会发生这种情况,以及如何将其修复为只有两个原型对象,其中simplebean1持有一个prototypebean,simplebean2持有另一个prototypebean
1条答案
按热度按时间vlju58qv1#
简介
请考虑代码的以下部分:
你对未来有什么期待
prototypeBean
要引用的字段?它应该始终是同一个示例吗
PrototypeBean
?或者它应该以某种方式包含原型逻辑?
原型意味着,每次我们向ioc容器请求bean时,它都会返回一个新示例
使用默认配置时(不指定
proxyMode
),字段将显示为相同的原型示例但当你指定
TARGET_CLASS
或者INTERFACES
那就不是PrototypeBean
示例将被注入,但其代理(请将作用域bean视为依赖项):也就是说,您需要注入一个代理对象,该代理对象公开与作用域对象相同的公共接口,但也可以从相关作用域(如http请求)检索真实的目标对象,并将方法调用委托给真实对象。
当范围
prototype
,然后:对共享代理的每个方法调用都会导致创建一个新的目标示例,然后将调用转发到该示例。
即调用任何方法,包括
toString
方法,在SimplePrototypeBean
bean,spring创建SimplePrototypeBean
在下面调用上的方法。另一个mcve
您可以尝试以下mcve来获得理解:
我们的班级
main
:它是一个spring引导应用程序
RandomHolder
是ioc容器中的一个原型bean(与您声明getPrototypeBean
豆子)这个
RandomHolder
有一个我们期望相同的领域。当我们运行应用程序时,从
getRandom
方法可以不同,下面是一个示例输出:我们现在知道
randomHolder
引用代理,当在代理上调用方法时,的新目标示例RandomHolder
并对其调用方法。您可以想象代理如下所示:
也就是说,它有创造的能力
RandomHolder
并在新示例上调用方法。不带proxymode=scopedproxymode.target\u类
当我们放下武器
proxyMode
参数:输出相同
spring不会创建代理,但会在每次请求时创建一个新示例
如果我们添加另一个组件:
然后输出可以是:
所以我希望在调用simplebean1和simplebean2时只创建2个原型示例。
你的期望有点不准确,你有很多这样的例子
prototype
创建bean的次数与调用任何方法的次数相同。有人能解释一下为什么会这样吗
我希望,我的解释足够清楚
以及如何将其修复为只有两个原型对象,其中simplebean1持有一个prototypebean,simplebean2持有另一个prototypebean
这里的问题不在原型范围内,而是在
SimpleBean
:这是一个singleton
,所以您有相同的SimpleBean
当您这样做时:只需在测试方法中添加一个Assert:
不会失败的。
再一次,希望这有帮助。