\nHow can i do so?
\nThanks
You can try factory pattern with spring scope prototype like below. Define a Abstract Factory Class which will give you MyInterface
object
public abstract class MyInterfaceFactoryImpl implements MyInterfaceFactory {\n\n@Override\npublic abstract MyInterface getMyInterface();\n\n}\n
\n\nThen define the Spring bean.xml file as below. Please note myinterface
bean is defined as prototype ( So it will always give you new instance).
<bean name=\"myinterface\" class=\"com.xxx.MyInterfaceImpl\" scope=\"prototype\"/>\n
\n\nThen define the factorybean with factory method name.
\n\n<bean name=\"myinterfaceFactory\" class=\"com.xxx.MyInterfaceFactoryImpl\">\n <lookup-method bean=\"myinterface\" name=\"getMyInterface\" />\n</bean>\n
\n\nNow you can call myinterfaceFactory
to get new instance.
for (OtherClass obj : someList) {\n MyInterface myInter = myInterfaceFactory.getMyInterface();\n Thread t = new Thread(myInter);\n t.start();\n}\n
\n","author":{"@type":"Person","name":"Himanshu Ahire"},"upvoteCount":15}}}Reputation: 4518
I have an interface called MyInterface
. The class that implements MyInterface
(lets call it MyImplClass
) also implements the Runnable
interface so i can use it to instantiate threads. This is my code now.
for (OtherClass obj : someList) {
MyInterface myInter = new MyImplClass(obj);
Thread t = new Thread(myInter);
t.start();
}
What i want to do is to declare the implementing class in my ApplicationContext.xml and get a new instance for each iteration. So my code will look something like this:
for (OtherClass obj : someList) {
MyInterface myInter = // getting the implementation from elsewhere
Thread t = new Thread(myInter);
t.start();
}
I want to still keep the IoC pattern if possible.
How can i do so?
Thanks
Upvotes: 9
Views: 53627
Reputation: 2826
Initial Note 1
Instead of creating and starting threads by hand, I would suggest to use a pool of threads that is externally configured, so that you can manage the number of threads that are created. If the size of someList
is 1000, creating so many threads is inefficient. You should better use an executor backed by a pool of threads. Spring provides some implementations that can be used as spring beans configured with the task
namespace, something like this:
<task:executor id="executor" queue-capacity="10" rejection-policy="CALLER_RUNS" />
queue-capacity
is the max size of the threads pool. If that size is exceeded, the current thread will run the additional task, thus blocking the loop until another thread is freed (rejection-policy="CALLER_RUNS"
). See the task:executor
documentation, or define any ThreadPoolExecutor
(spring or jdk-concurrent) with your own configuration.
Initial Note 2
If the only state that you intend to store in MyClassImpl
is the item from the list, then you can forget the rest of the explanation below (except for the ThreadPool stuff), and directly use a singleton bean : remove the Runnable
interface and its no-arg run()
method, add a run(OtherClass obj)
method and do something like this:
final MyInterface task = // get it from spring as a singleton
for (final OtherClass obj : someList) {
executor.execute(new Runnable() {
public void run() {task.run(obj);}
});
// jdk 8 : executor.execute(task::run);
}
If you plan to store some state inside MyClassImpl during the execution of run()
(other than the processed object), go on reading. But you will still use the run(OtherClass obj)
method instead of no-args run()
.
The basic idea is to get a different object for each running thread, based on some kind of model or prototype defined as a spring bean. In order to achieve this, just define the bean that you initially want to pass to each thread as a proxy that dispatches to an instance that is bound to the running thread. This means that the same instance of task is injected into each thread, and during the thread execution, the real task on which you invoke methods is bound to the current thread.
Main program
Since you are using the elements of the list to do your business, you will pass each element to its owning task.
public class Program {
@Resource private MyInterface task; // this is a proxy
@Resource private TaskExecutor executor;
public void executeConcurrently(List<OtherClass> someList) {
for (final OtherClass obj : someList) {
executor.execute(new Runnable() {
public void run() { task.run(obj); }
});
// jdk 8 : executor.execute(task::run);
}
}
}
We suppose that Program
is a spring bean, thus the dependencies can be injected. If Program
is not a spring bean, you will need to get the spring ApplicationContext from somewhere, then autowire Program
(i.e. inject dependencies found in the ApplicationContext, based on annotations). Something like this (in the constructor) :
public Program(ApplicationContext ctx) {
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
Define the task
<bean id="taskTarget" class="MyImplClass" scope="prototype" autowire-candidate="false" />
<bean id="task" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName" value="taskTarget"/>
<property name="targetClass" value="MyInterface"/>
</bean>
</property>
</bean>
taskTarget
is where you define your business. This bean is defined as a prototype, as a new instance will be allocated to each thread. Thanks to this, you can even store state that depends on the run()
parameter. This bean is never used directly by the application (thus autowire-candidate="false"
), but it is used through the task
bean. In executeConcurrently()
above, the line task.run(obj)
will actually be dispatched on one of the prototype taskTarget
that was created by the proxy.
Upvotes: 2
Reputation: 717
You can try factory pattern with spring scope prototype like below. Define a Abstract Factory Class which will give you MyInterface
object
public abstract class MyInterfaceFactoryImpl implements MyInterfaceFactory {
@Override
public abstract MyInterface getMyInterface();
}
Then define the Spring bean.xml file as below. Please note myinterface
bean is defined as prototype ( So it will always give you new instance).
<bean name="myinterface" class="com.xxx.MyInterfaceImpl" scope="prototype"/>
Then define the factorybean with factory method name.
<bean name="myinterfaceFactory" class="com.xxx.MyInterfaceFactoryImpl">
<lookup-method bean="myinterface" name="getMyInterface" />
</bean>
Now you can call myinterfaceFactory
to get new instance.
for (OtherClass obj : someList) {
MyInterface myInter = myInterfaceFactory.getMyInterface();
Thread t = new Thread(myInter);
t.start();
}
Upvotes: 15
Reputation: 42834
Given the context you provided in your comment to me, I would suggest you don't have the MyImplClass
instances created by Spring. Having this prototyped object instantiated by Spring provides no benefit from what I can tell.
The best way, in my opinion, to keep with the IoC pattern here would be to instead utilize a Spring managed Factory that produces instances of MyImplClass
. Something along the lines of this:
public class MyInterfaceFactory {
public MyInterface newInstance(final OtherClass o) {
return new MyImplClass(o);
}
}
Depending on the usage needs, you can modify this factory's interface to return MyImplClass
, or add some logic to return a different implementation of MyInterface
.
I tend to think that Factories and IoC/DI work pretty well together, and your use case is a pretty good example of that.
Upvotes: 2
Reputation: 1002
First and foremost, we all know that by default spring container will create bean in singleton mode (if you don't explicitly specify the scope). As the name implies, singleton guarantee that everytime you call the bean, it will give you the same instance. Nevertheless, there's slightly differences between singleton in spring with the one singleton that mentioned by GoF. In Spring, the created instance will be restricted to the container (not JVM as we found in GoF).
Additionally, in spring, you can define two different bean instances of the same type but with different names and they will be two different instances created on the heap. But every time you reference one of those beans by name (ref= in a bean definition or getBean on the appContext), you get the same object every time. That is obviously different than the actual singleton pattern but similar in concept anyway.
Generally speaking, there are implications of using a singleton in a multi-threaded application (Spring singleton or actual singleton). Any state that you keep on these objects must account for the fact that multiple threads will access it. Usually, any state that exists will be set during instantiation via a setter or constructor argument. This category of Spring bean makes sense for long lived objects, thread-safe objects. If you want something thread specific and still desire spring to create the object, then prototype scope works.
Upvotes: 0
Reputation: 379
Keep the spring configuration file, beans.xml in the root of the classpath. Making scope=prototype, will result in different instances of bean for each getBean method invocation.
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myinterface" class="MyImplClass" scope="prototype"/>
</beans>
Similar way if you want Spring to return the same bean instance each time one is needed, you should declare the bean's scope attribute to be singleton.
Once the IoC container is initialized, you can retrieve your Spring beans. But make sure, you do the below only initialization only once.
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Then you can change your code as below.
for (OtherClass obj : someList) {
MyInterface myInter = (MyInterface ) context.getBean("myinterface");
Thread t = new Thread(myInter);
t.start();
}
Upvotes: 2
Reputation: 26
If you can determine at runtime which MyImplClass
instance to use, you could list all implementations as beans in your context xml and @Autowire
an array of type MyInterface
to get all MyInterface
implementors.
Given the following in the context xml:
<bean class="MyImplClass" p:somethingCaseSpecific="case1"/>
<bean class="MyImplClass" p:somethingCaseSpecific="case2"/>
Then a deceleration
@Autowire
MyInterface[] allInterfaceBeans;
will result in allInterfaceBeans
containing both beans defined above.
If you wanted the logic for determining which implementation to use to be done at injection time, you could always @Autowire
a setter method setAllInterfaceBeans(MyInterface[] allInterfaceBeans);
.
Upvotes: 0