假设有一个应用程序在每次需要处理一些数据时都会创建一个 Task 类的实例。任务实例中注入了一些其他服务,但所有这些服务和任务对象本身在单个任务实例中都是唯一的。当然也注入了一些全局服务,但它们是真正的应用程序范围的单例。所以我的问题是配置注入本地(或作用域)单例实例的最佳方法是什么?我主要考虑使用子上下文,但如何正确配置它仍然是我的问题。还要提到的一件事是我使用注释和基于 java 的配置。
4 回答
我认为自定义范围是您所要求的。但是,请注意:您所描述的痛点通常是由于过度紧密耦合的设计造成的,而不是在 IOC 容器内部的合理需要。您可能是真正有这种合法需求的少数人之一,但重新设计更有可能以更清洁的方式解决您的问题。
private static final SingletonObject singleton = new SingletonObject();
Private 只能在本地访问。静态只做一个。最终阻止它改变。
如果您需要阻止其他人创建更多 SingletonObjects,我将需要更多上下文信息并且可能是不可能的 - 但在大多数情况下,不阻塞这实际上不是问题。
如果我没记错的话,你想让
“任务”类有两个实例变量,因为
“子任务”每个任务实例应该只有一个实例
“全局任务”每个应用程序/Spring IOC 上下文应该只有一个实例,
并且每次创建“任务” " 您要创建 unquie "SubTask" 的实例并使用相同的 GlobalTask 实例。
如果这是真的,我不明白
你可以通过将“Task”和“SubTask”声明为原型并将“GlobalTask”作为默认的 SingleTon 来解决什么问题,如下所示
@Component("Task")
@Scope("prototype") 公共类任务 {
public Task(){
System.out.println("Task Created");
}
@Autowired
SubTask subTask;
@Autowired
GlobalTask globalTask;
public GlobalTask getGlobalTask() {
return globalTask;
}
public void setGlobalTask(GlobalTask globalTask) {
this.globalTask = globalTask;
}
public SubTask getSubTask() {
return subTask;
}
public void setSubTask(SubTask subTask) {
this.subTask = subTask;
}
}
@Component("SubTask")
@Scope("prototype") public class SubTask { public SubTask() { System.out.println("SubTask Created"); } public void performTask(){ System.out.println("执行任务"); } }
@Component("GlobalTask")
公共类 GlobalTask {
public GlobalTask(){
System.out.println("Global task created");
}
public void performTask(){
System.out.println("Perform Global Task");
}
}
我最终想出的解决方案需要创建一个子上下文。关键是要指定不同的子配置,以便父上下文不知道子组件的依赖关系。最简单的解决方案是创建一个启用组件扫描的单独 java 配置并将其放入专用包中。
@Configuration
@ComponentScan
public class TaskConfig {}
public interface TaskFactory {
Task createTask();
}
@Component
public class TaskFactoryImpl implements TaskFactory {
private ApplicationContext parentContext;
@Autowired
public void setParentContext(ApplicationContext parentContext) {
this.parentContext = parentContext;
}
@Override
public Task createTask() {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
context.register(TaskConfig.class);
context.setParent(parentContext);
context.refresh();
return context.getBean(Task.class);
}
}
}