Get a new spring bean instance

I have an interface called MyInterface . The class that implements MyInterface (allows you to call it MyImplClass ) also implements the Runnable interface, so I can use it to create 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 declare an implementation 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 save the IoC template if possible.
How can i do this?
Thanks

+8
java spring inversion-of-control
source share
6 answers

You can try the factory template with the spring prototype as shown below. Define an abstract factory class that will give you a MyInterface object

 public abstract class MyInterfaceFactoryImpl implements MyInterfaceFactory { @Override public abstract MyInterface getMyInterface(); } 

Then define the spring bean.xml file as shown below. Please note: MyInterface bean is defined as a prototype (so it will always give you a new instance).

 <bean name="myinterface" class="com.xxx.MyInterfaceImpl" scope="prototype"/> 

Then define a factory with the factory method name.

 <bean name="myinterfaceFactory" class="com.xxx.MyInterfaceFactoryImpl"> <lookup-method bean="myinterface" name="getMyInterface" /> </bean> 

Now you can call myinterfaceFactory to get a new instance.

 for (OtherClass obj : someList) { MyInterface myInter = myInterfaceFactory.getMyInterface(); Thread t = new Thread(myInter); t.start(); } 
+12
source share

Save the spring configuration file, beans.xml in the root directory of the class path. Creating scope = prototype will result in different bean instances for each call to the getBean method.

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> 

Similarly, if you want spring to return the same bean every time you need it, you must declare the bean scope attribute equal to one.

After initializing the IoC container, you can get spring beans. But make sure that you do below only initialization only once.

 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 

Then you can change your code as shown below.

 for (OtherClass obj : someList) { MyInterface myInter = (MyInterface ) context.getBean("myinterface"); Thread t = new Thread(myInter); t.start(); } 
+2
source share

Given the context that you indicated in your comment on me, I would suggest that you do not have instances of MyImplClass created by Spring. Having this prototype object created by Spring does not give any benefit to what I can say.

The best way, in my opinion, to stick with the IoC pattern would be to use Spring Factory, which creates instances of MyImplClass . Something like that:

 public class MyInterfaceFactory { public MyInterface newInstance(final OtherClass o) { return new MyImplClass(o); } } 

Depending on your usage needs, you can change this Factory interface to return MyImplClass , or add some logic to return another implementation of MyInterface .

I tend to think that Factories and IoC / DI work well together, and your use case is a pretty good example of this.

+2
source share

Initial Note 1

Instead of manually creating and starting threads, I would suggest using a thread pool that is configured externally so that you can control how many threads are created. If the size of someList is 1000, creating so many threads is inefficient. It is better to use an artist supported by a thread pool. 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 - maximum thread pool size. If this size is exceeded, the current thread starts an additional task, thereby 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.

Original Note 2

If the only state you are going to store in MyClassImpl is an element from the list, you can forget the rest of the explanation below (except for ThreadPool) and use the singleton bean directly: remove the Runnable interface and its no-arg run() method, add run(OtherClass obj) and follow these steps:

 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 save some state inside MyClassImpl during run() (except for the processed object), continue reading. But you will still use the run(OtherClass obj) method instead of no-args run() .

The main idea is to get a separate object for each working thread based on some model or prototype defined as a Spring bean. To do this, simply define the bean that you initially want to pass to each thread as a proxy server that sends the instance associated with the current thread. This means that the same task instance is injected into each thread, and during the execution of the thread, the real task that you are calling the methods is bound to the current thread.

Main program

Since you use list items for your activities, you will transfer each item to its own 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); } } } 

Suppose Program is a Spring bean, so dependencies can be introduced. If the Program not a Spring bean, you will need to get W760> ApplicationContext, and then the autowire Program (that is, nest the dependencies found in ApplicationContext based on annotations). Something like this (in the constructor):

 public Program(ApplicationContext ctx) { ctx.getAutowireCapableBeanFactory().autowireBean(this); } 

Define a 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, since a new instance will be allocated for each thread. Thanks to this, you can even save a 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 string task.run(obj) will actually be sent to one of the prototypes of the taskTarget that the proxy created.

+2
source share

If you can determine at runtime an instance of MyImplClass to use, you can list all implementations as beans in your xml context and an @Autowire array of type MyInterface to get all MyInterface constructors.

Given the following in the context of xml:

 <bean class="MyImplClass" p:somethingCaseSpecific="case1"/> <bean class="MyImplClass" p:somethingCaseSpecific="case2"/> 

Then braking

 @Autowire MyInterface[] allInterfaceBeans; 

will result in an allInterfaceBeans containing as beans defined above.

If you need logic to determine which implementation to use during injection, you can always @Autowire setter setAllInterfaceBeans(MyInterface[] allInterfaceBeans); .

0
source share

First of all, we all know that by default, the spring container creates a bean in single-point mode (unless you explicitly specify an area). As the name implies, singleton ensures that every time you call a bean, it will give you the exact same instance. However, there are slight differences between the singleton in spring with the one singleton mentioned by GoF. In Spring, the instantiated instance will be limited to the container (not the JVM, as we found in GoF).

In addition, in Spring, you can define two different instances of a bean of the same type, but with different names, and they will be two different instances created on the heap. But each time you refer to one of these beans by name (ref = in the definition of bean or getBean on appContext), you get the same object every time. This obviously differs from the actual singleton pattern, but in any case is similar to the concept.

Generally speaking, there are consequences of using single-point in a multi-threaded application (Spring singleton or actual singleton). Any state that you hold on these objects should take into account the fact that several threads will access it. Usually, any state that exists will be set during instance creation via the setter or constructor argument. This category of spring bean makes sense for long-lived objects, thread-safe objects. If you want a specific theme and still want spring to create an object, then the prototype area works.

0
source share

All Articles