Question

Let's say there is an application that creates an instance of the Task class every time when it needs to process some data. The task instance have some other services injected into it but all this services and the task object itself are unique within a single task instance. Some global services are being injected too of course but they are true application wide singletons. So my question is what is the best way to configure injection of that local (or scoped) singleton instances? I am primarily thinking about using a child context but how to configure it properly is still a question to me. One more thing to mention is that I use annotations and java based configuration.

Was it helpful?

Solution 4

The solution I finally came up with requires to create a child context. The key point is to specify different child configuration so that parent context is unaware about child component dependencies. The simplest solution is to create a separate java config with enabled component scanning and to place it into a dedicated package.

@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);
        }
    }
}

OTHER TIPS

I think custom scopes are what you're asking for. However, some words of caution: typically the pain point you're describing results from an overly tightly coupled design rather than a legitimate need to get up to your elbows in the internals of the IOC container. You might be one of the few people that actually do have that legitimate need, but it's far more likely that a redesign would solve your problem in a much cleaner way.

 private static final SingletonObject singleton = new SingletonObject();

Private to make only accessible locally. Static to make only one. Final to stop it getting changed.

If you needed to prevent other people creating more SingletonObjects I would need more context info and may not be possible - but in most cases not blocking that is not actually a problem.

If i am not wrong , you wanted to have
"Task" class two instance variables as
"SubTask" should be only one instance per Task instance
"GlobalTask" Should be only one instance per Application / Spring IOC Context
And Each time you create "Task" instance you want to create unquie "SubTask" and use the same GlobalTask instance.

if this is true , i dont understand what is the problem
you can achieve by declaring "Task" and "SubTask" as prototype and "GlobalTask" as default as SingleTon as below

@Component("Task")

@Scope("prototype") public class Task {

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("Perform Task"); } }

@Component("GlobalTask")

public class GlobalTask {

public GlobalTask(){
    System.out.println("Global task created");
}

public void performTask(){
    System.out.println("Perform Global Task");
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top