9

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

Mr T.
  • 4,278
  • 9
  • 44
  • 61
  • 1
    did you try this ? `MyClass myClass = applicationContext.getBean("myClass");` – Aditya Peshave Apr 07 '15 at 15:34
  • also take a look at the answer of this question. http://stackoverflow.com/questions/812415/why-is-springs-applicationcontext-getbean-considered-bad – Aditya Peshave Apr 07 '15 at 15:35
  • 1
    As i understand - `ApplicationContext.getBean` is not IoC. also, the link that you proposed suggests a single instance solution. for this i can use Inject annotaion - which is a more general (not spring dependent). – Mr T. Apr 07 '15 at 15:46
  • @MrT Why you want to create multiple instances of a bean? Is that for reasons of thread safety or what?? – MCHAppy Apr 07 '15 at 15:52
  • 1
    @ChakerMallek - lets say for now that its because of thread safety. The thread calls a web resource with parameters according to the obj given in the constructor so yes - i need multiple instances of a defined class – Mr T. Apr 07 '15 at 16:03
  • How do you plan to declare `MyImplClass` in your application context if it is taking a value into its constructor from your loop? Is `someList` defined in your application also, or does it come from the request some how? – nicholas.hauschild Apr 07 '15 at 16:08
  • @MrT The different threads in the multithreaded application will not be able to access the bean until it completes the work assigned to it. Effectively, using the spring with default scope i.e. singleton will make multithreaded application to do the task in sequential fashion. – MCHAppy Apr 07 '15 at 16:10
  • @nicholas.hauschild - i could always add a setter to the interface and set the external object from there. Some list is a dynamically built list. – Mr T. Apr 07 '15 at 16:35
  • @ChakerMallek - can you please explain your last comment? the whole idea of the threads is to do them asynchronous – Mr T. Apr 07 '15 at 16:37
  • 1
    @MrT. Forget about the last comment. Let's explain things further: Stateless objects in spring are always be shared and treated as singleton and created once in context of IoC container. Stateful are treated as prototype so object will be created every time when it's request by IoC container.So in Multithreaded environment you need both type. As DataSource object instantiated only once per application and shared by all objects so it's required to be Singleton and Prototype like your POJO objects. – MCHAppy Apr 07 '15 at 16:46
  • Also, prototype beans and Singleton beans can both hold state. However, according to the Spring documentation, "you should use the prototype scope for all beans that are stateful, while the singleton scope should be used for stateless beans." – MCHAppy Apr 07 '15 at 16:48
  • You say _What i want to do is to declare the implementing class in my ApplicationContext.xml_, but then you don't want to get it from a Spring `ApplicationContext`. You **need** a container. – Sotirios Delimanolis Apr 08 '15 at 01:59
  • You can refer my answer for a similar question [Autowire of prototype bean into prototype bean?](http://stackoverflow.com/a/38128289/1401019). – Sundararaj Govindasamy Jun 30 '16 at 16:12

6 Answers6

15

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();
}
Himanshu Ahire
  • 677
  • 5
  • 18
2

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();
}
Albin
  • 371
  • 1
  • 4
  • 18
  • Thanks but this solution is spring dependent as in that the injection mechanism must be spring. That alone makes it not IoC. Worst case scenario, indeed i will use this solution, but i was wondering how to stay within the IoC pattern – Mr T. Apr 07 '15 at 16:31
  • Solution by @Himorithm will work fine. Go thorugh http://docs.spring.io/spring/docs/4.1.6.RELEASE/spring-framework-reference/html/beans.html#beans-factory-method-injection – Albin Apr 08 '15 at 15:07
2

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.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
2

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.

Gaetan
  • 2,802
  • 2
  • 21
  • 26
0

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);.

Ben Kern
  • 26
  • 2
  • Thanks but from what i understand from your solution is that i get a single instance of each implementing class where i need multiple instances of the implementing class (and i don't care what class that might be) – Mr T. Apr 07 '15 at 16:32
0

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.

MCHAppy
  • 1,012
  • 9
  • 15