实现组件范围单例的最佳方法是什么?

时间:2013-12-11 15:50:11

标签: java singleton spring-ioc spring-java-config

假设有一个应用程序在每次需要处理某些数据时都会创建Task类的实例。任务实例注入了一些其他服务,但所有这些服务和任务对象本身在单个任务实例中是唯一的。一些全球服务当然也在注入,但它们是真正的应用程序范围的单例。所以我的问题是配置注入本地(或作用域)单例实例的最佳方法是什么?我主要考虑使用子上下文,但如何正确配置它仍然是一个问题。还有一点要提到的是我使用注释和基于java的配置。

4 个答案:

答案 0 :(得分:1)

我认为custom scopes是你所要求的。但是,有些注意事项:通常你所描述的痛点来自于过度紧密耦合的设计,而不是合法的需要在IOC容器内部到达你的肘部。你可能是少数几个真正有合法需求的人之一,但重新设计更有可能以更清洁的方式解决你的问题。

答案 1 :(得分:0)

 private static final SingletonObject singleton = new SingletonObject();

私有,只能在本地访问。 静态只做一个。 最后阻止它改变。

如果你需要阻止其他人创建更多的SingletonObjects,我需要更多的上下文信息,而且可能无法实现 - 但在大多数情况下,不阻塞实际上并不是问题。

答案 2 :(得分:0)

如果我没错,你想拥有
“任务”类将两个实例变量视为
  “SubTask”应该只是每个Task实例的一个实例   “GlobalTask​​”应该只是每个Application / Spring IOC上下文的一个实例 每次创建“任务”实例时,您都要创建unquie“SubTask”并使用相同的GlobalTask​​实例。

如果这是真的,我不明白是什么问题
你可以通过声明“Task”和“SubTask”作为原型来实现,“GlobalTask​​”默认为SingleTon,如下所示

@Component("Task")

@Scope( “原型”) 公共课程任务{

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( “原型”) 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");
}

}

答案 3 :(得分:0)

我最终提出的解决方案需要创建子上下文。关键是指定不同的子配置,以便父上下文不知道子组件依赖性。最简单的解决方案是创建一个单独的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);
        }
    }
}