java - 在 Spring 中,为什么具有范围原型的服务会多次实例化?
问题描述
我创建了一个 Spring 项目并创建了以下文件,因为我试图了解 Spring 如何处理单例与非单例组件类:
调度程序.java:
@Component
public class ScheduledTasks {
@Autowired
private TestRun testRun;
@Scheduled(cron= "*/15 * * * * *")
public void startTest() {
testRun.startNewRun();
}
}
测试运行.java
@Service
public class TestRun {
private long t = System.currentTimeMillis();
@Autowired
private TestService testService;
public void startNewRun() {
new Thread(new TestRun.TestRunThread()).start();
}
public TestRun(){
System.out.println("TestRun Constructor " + t);
}
public class TestRunThread implements Runnable {
public void run() {
testService.toString();
System.out.println("Counta " + testService.getCount());
System.out.println("Countb " + testService.getCount());
}
}
}
测试服务.java
@Service
@Scope(value="prototype", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class TestService {
private long t = System.currentTimeMillis();
private (volatile) int count; //Tried both with and without volatile
public TestService(){
System.out.println("Service Constructor " + t);
}
public int getCount(){
return count++;
}
}
运行后我的期望是:类 TestRun 将被实例化一次(真)并显示“TestRun 构造函数 {毫秒}”(真)但是虽然我期望 TestService 构造函数会被调用多次(每次启动一个新线程) 是真的,下面的输出我无法解释:
TestRun Constructor 1612706390893
...
TestService Constructor 1612706399976
Counta 0 ; 1612706390893
TestService Constructor 1612706400011
Countb 0 ; 1612706390893
TestService Constructor 1612706415006
Counta 0 ; 1612706390893
TestService Constructor 1612706415009
Countb 0 ; 1612706390893
'Counta' 后面的 0 我理解,但为什么 'Countb' 后面的计数也是 0?从日志中我得出结论,在调用“testService.getCount()”方法时再次实例化了 TestService,但我不明白为什么会这样。任何帮助,将不胜感激。
解决方案
出现问题是因为您使用ScopedProxyMode.TARGET_CLASS
的是原型bean。很可能 CGLIB 正在生成一个包装器,并且每次调用TestService
都会创建一个新实例,例如
// CGLIB proxy
class TestServiceProxy extends TestService {
...
public int getCount() {
final TestService testService = ...
return testService.getCount();
}
}
我实际上为您运行了一个示例。
您可以看到调试调用堆栈,并注意到 CGLIB 生成了一个包装器。
移除ScopedProxyMode.TARGET_CLASS
@Service
@Scope("prototype")
public class TestService {
从代理中释放调用堆栈,并显示预期结果。
推荐阅读
- python-3.x - Python Pandas : Extend operation of a column if a condition matches
- php - 如何将while循环数据存储在字符串变量中,然后在php的邮件函数中使用它
- ruby-on-rails - Rails 应用程序中的许多属性会使用(更多)更多内存吗?
- jquery - 尝试从多选下拉菜单中添加所选项目的值
- php - 后台任务 Symfony
- python - 如何在尝试从 docker+nginx+uwsgi+flask 保存和提供文件时修复“Permission Denied”错误
- django - 如何在 JSON 对象元素中进行计算
- java - Note5读取Mifare经典卡UID
- apache-spark - 我想知道如何在 pyspark 中执行 mlxtend stacking CV regressor
- kubernetes - 如何在 terraform 中导入生成的 Kubernetes 集群的命名空间