This is an exotic use-case, so it requires some patience to understand and may require exotic solutions.
The Context
I'm making a library to be used with Spring that performs automatic actions upon specific bean instances present in the context, created by #Bean methods and not by #ComponentScan. If at all possible, the beans should be distinguishable not by type, but by other means, preferably annotations on the factory method.
Here's the ideal case. E.g. let's say there are 2 bean-producing methods:
#Bean
public SomeType makeSome() {...}
#Bean
#Special
public SomeOtherType makeOther() {...}
Here, the second bean is special because of the #Special annotation on method that created it. But any mechanism of making it distinguishable is an option.
Then, I want to somehow get only the special beans.
The Caveat
I'm aware that if all the beans would implement the same interface, I could inject them by type. But this should work as transparently as possible, requiring as little change to an existing app as possible.
The potential approaches
Here's two broad approaches I have in mind:
1) Jack into the process of registering beans, and transparently wrap the bean instances into some sort of a container (I'm quite certain this part is doable). E.g.
public void registerBean(Object bean, ApplicationContext ctx) {
ctx.register(bean); //do the usual
ctx.register(new Wrapper(bean); //register it wrapped as well
}
Then, inject all all beans of type Wrapper. The problem here is obviously the duplication... Alternatively I could maybe generate a proxy instance on the fly that would implement a Wrapper interface, so it could at the same time act as the original bean and as a wrapper. I did say I'm OK with exotic solutions too, didn't I?
2) Spring already distinguishes bean candidates from actual registered beans (e.g. #ComponentScan can filter the candidates by package, annotations etc). I'm hoping to maybe jack into this process and get a hold of candidate descriptors that still contain some useful metadata (like their factory method) that would allow me to later distinguish those bean instances.
Seems like you need to use #Qualifier it provides functionality to distinguish beans:
#Bean
#Qualifier("special")
class MyBean {}
#Bean
class OtherBean {
#Qualifier("special")
private MyBean bean;
}
You can read about it more there: https://spring.io/blog/2014/11/04/a-quality-qualifier
UPD (understood what you are talking about :) )
You may want to take a look at BeanDefinitionRegistryPostProcessor
Here a usage sample:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.util.Collections.unmodifiableMap;
/**
* This is hack to collect all beans of some type in single map without eager initialization of those beans
*
* Usage:
* 1. Register new bean of type {#link ServiceTrackingBeanPostProcessor} parametrized with class of
* beans you want to collect
* 2. Now you can inject {#link ServiceTracker} parametrized with your type anywhere
*
* #param <T> Located type
*/
public class ServiceTrackingBeanPostProcessor<T> implements BeanPostProcessor, BeanDefinitionRegistryPostProcessor {
private final ConcurrentMap<String, T> registeredBeans = new ConcurrentHashMap<>();
private final Class<T> clazz;
private final String beanName;
public ServiceTrackingBeanPostProcessor(Class<T> clazz) {
this.clazz = clazz;
beanName = "locatorFor" + clazz.getCanonicalName().replace('.', '_');
}
#Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
#Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
if (!clazz.isInstance(o)) {
return o;
}
registeredBeans.putIfAbsent(s, (T) o);
return o;
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
AnnotatedGenericBeanDefinition def = new AnnotatedGenericBeanDefinition(Wrapper.class);
registry.registerBeanDefinition(beanName, def);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerSingleton(beanName, new Wrapper(unmodifiableMap(registeredBeans)));
}
private class Wrapper extends AbstractServiceTracker<T> {
public Wrapper(Map<String, T> services) {
super(services);
}
}
}
You just need to change the condition of check from clazz.isInstance to obtainment of beanDefinition from application context by bean name where you could get almost any information about instantiation and annotations
Here is one way to get all beans with #Special annotation.
Map<String,Object> beans = applicationContext.getBeansWithAnnotation(Special.class);
Reference: https://stackoverflow.com/a/14236573/1490322
EDIT: The above answer seems to work only when the class is annotated with #Special, so it will not work for your scenario. But this other answer to the same question might work. It uses meta data from the ConfigurableListableBeanFactory to identify any beans whose methods were annotated with a specific annotation.
I think as mentioned #Qualifier annotation is a way to go here. But I will show different example:
#Bean
public SomeType makeSome() {...}
#Bean
public SomeType makeSomeOther() {...}
in your component (#Service) where you want this bean you can:
#Autowired
#Qualifier("makeSome")
SomeType makeSomeBean;
As you see two beans with same type can be distinguished by bean name (Bean assigned with same name as #Bean annotated method named)
Related
Suppose I have interface foo and bar, then have multiple classes that implements both of them:
public interface InterfaceFoo{
int getFoo()
}
public interface InterfaceBar{
int getBar()
}
public class FooBarOne implements InterfaceFoo, InterfaceBar{
public int getFoo() { ... }
public int getBar() { ... }
}
public class FooBarTwo implements InterfaceFoo, InterfaceBar{
public int getFoo() { ... }
public int getBar() { ... }
}
Then I create beans for both of these classes:
#Configuration
#ComponentScan
public class Config {
#Bean
fooBarOne getFooBarOne() { return new FooBarOne(); }
#Bean
fooBarTwo getFooBarTwo() { return new FooBarTwo();}
}
Finally another bean which #Autowries in a list of all implementations of foo
#Configuration
#ComponentScan
public class FooConfig {
#Bean
#Autowired
public List<InterfaceFoo> fooFetcher(List<<InterfaceFoo>> listFoos) {
return listFoos;
}
}
My question is, how does Spring identify/autowire beans when they have multiple implementations of an interface? The above pseudo code seems to work, however, if I change the return type of the bean from the concrete class to an ibar, it is not picked up by the autowire:
#Configuration
#ComponentScan
public class Config {
#Bean
InterfaceBar getFooBarOne() { return new FooBarOne(); }
#Bean
InterfaceBar getFooBarTwo() { return new FooBarOne(); }
}
From the example above, spring does not pick these beans up when autowiring for implementations of ifoo. Switching the return type to ifoo works, which implies to me that spring looks at the return type of the bean rather than that of the returned object? Even though fooBarOne and fooBarTwo both implement foo and bar, do I need to return either the concrete class or interface ifoo if I want the autowire for List to pick it up?
Spring's default autowire mode is by type, so it makes sense that if you create two beans of type iBar, they will not be autowired as iFoo, even though the concrete classes are also instances of iFoo. Spring does not know about all of the interfaces that a class implements, it only knows of the type of beans that were created in its context.
When you attempt to autowire List<<iFoo>>, Spring will look in its context for all the beans of type iFoo to inject, which you have none.
Also, please read up on the Java naming conventions, you probably want your interfaces to just be Foo and Bar https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html
When declaring beans with #Bean-annotated methods, Spring assigns return type of the method as bean type, i.e. saves class name (ibar.class.getName()) to BeanDefinition, along with other object metadata. From now, spring does not care whether your class implements other interfaces, it just has your object and assigned type.
When autowiring, spring filters beans that match bean type and name constrains, provided by type of bean to be constructed
In this case, when trying to create List<iFoo>, spring can hook beans with type iFoo or types extending/implementing it, but not ibar, because ibar is not related to iFoo
If you need just List<iFoo>, and you are not using fooBarOne/fooBarTwo beans, practically it does not matter if you declare bean as iFoo or fooBarOne. But in general, you should prefer using interfaces over implementations, it will help to keep Dependency Inversion in your code.
And, always name your classes with capital letter.
#Named("myUniqueName")
public class ReportDashboardDao implements DashboardDAO{
//STUFF
}
how can i access the string inside #Named tag when i am injecting DashboardDAO like this :
#Named
public class DshboardDaoConsumer(){
#Inject List<DashboardDAO> dashboardDAO;
//STUFF
}
Use a Map instead
#Inject
Map<String, DashboardDao> dashBoardDaos;
This will inject a Map with bean names as keys and daos as values.
Of course, you could also read the annotation value from class instances.
You can't. You're injecting by type. After injection has been done, Spring does not leave behind any relation between the bean's object and the bean's name.
You might want to check out ApplicationContext#getBeanNamesByType() depending on what you want to do.
By implementing BeanNameAware.
#Named("myUniqueName")
public class ReportDashboardDao implements DashboardDAO, BeanNameAware{
//STUFF
private String beanName;
#Override
public Void setBeanName(String beanName) {
this.beanName = beanName;
}
}
So that Spring can inject the beanName into the bean. If you add a public String getBeanName(); in your DashboardDAO interface, DashboardDaoConsumer will be able to obtain it.
In this particular case, Spring will inject the name you specified in the annotation.
Let's assume I have this code:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService aService;
#RequestMapping("/doStuff")
public void doStuff(#RequestParam("type") String type) {
aService.doStuff();
}
}
In my application I need to call a specific service depending on the specified type. All services implements the same interface. If I understand correctly SomeService cannot be an interface. I could use a service factory and instantiate the service depending on the type every time a new request is done, but this doesn't look very efficient.
Alternatively I could use a different controller for each different type of service (and encode the type in the REST URI), but this would imply a lot of code duplication since all the services basically implements the same interface.
My question is, assuming the called service depends on the passed parameter, what is the best pattern to adopt for this scenario?
Similar to RC.'s answer, instead of using a Map and adding the values by you, just let the Spring BeanFactory handle this for you:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private BeanFactory beanFactory;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
SomeService aService = (SomeService)beanFactory.getBean(type);
aService.doStuff();
}
}
You could use a map here, something along this:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService someService;
#Autowired
private SomeOtherService someOtherService;
// ...
private final Map<String, ServiceCommonInterface> serviceMap = new HashMap<>();
#PostConstruct
private void postConstruct() {
serviceMap.put(typeForSomeService, someService);
serviceMap.put(typeForSomeOtherService, someOtherService);
}
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is correct (an enum might be handy here)
serviceMap.get(type).doStuff();
}
}
Or better, as stated in comments you can leverage qualifiers:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is a correct bean name
applicationContext.getBean(type, ServiceCommonInterface.class).doStuff();
}
}
Depending on the number of types you wish to support there are two options I see.
1) Autowire in a factory as you mentioned and lazily create each service as needed. If the services are stateless you could keep a reference to the object after created so would only need to create once per type.
2) Autowire in a Spring Map with the key being your types and the value being the correct service to use. Then when your receive the type, can retrieve the correct service impl for your map.
For example for map: http://www.mkyong.com/spring/spring-collections-list-set-map-and-properties-example/ or see How to inject a Map<String, List> in java springs?
Both of these require you to create an interface for your service which is something you said is possible.
Using Spring's Java Config, I need to acquire/instantiate a prototype-scoped bean with constructor arguments that are only obtainable at runtime. Consider the following code example (simplified for brevity):
#Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
where the Thing class is defined as follows:
public class Thing {
private final String name;
#Autowired
private SomeComponent someComponent;
#Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Notice name is final: it can only be supplied via a constructor, and guarantees immutability. The other dependencies are implementation-specific dependencies of the Thing class, and shouldn't be known to (tightly coupled to) the request handler implementation.
This code works perfectly well with Spring XML config, for example:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
How do I achieve the same thing with Java config? The following does not work using Spring 3.x:
#Bean
#Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
Now, I could create a Factory, e.g.:
public interface ThingFactory {
public Thing createThing(String name);
}
But that defeats the entire point of using Spring to replace the ServiceLocator and Factory design pattern, which would be ideal for this use case.
If Spring Java Config could do this, I would be able to avoid:
defining a Factory interface
defining a Factory implementation
writing tests for the Factory implementation
That's a ton of work (relatively speaking) for something so trivial that Spring already supports via XML config.
In a #Configuration class, a #Bean method like so
#Bean
#Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
is used to register a bean definition and provide the factory for creating the bean. The bean that it defines is only instantiated upon request using arguments that are determined either directly or through scanning that ApplicationContext.
In the case of a prototype bean, a new object is created every time and therefore the corresponding #Bean method is also executed.
You can retrieve a bean from the ApplicationContext through its BeanFactory#getBean(String name, Object... args) method which states
Allows for specifying explicit constructor arguments / factory method
arguments, overriding the specified default arguments (if any) in the
bean definition.
Parameters:
args arguments to use if creating a prototype using explicit arguments
to a static factory method. It is invalid to use a non-null args value
in any other case.
In other words, for this prototype scoped bean, you are providing the arguments that will be used, not in the constructor of the bean class, but in the #Bean method invocation. (This method has very weak type guarantees since it uses a name lookup for the bean.)
Alternatively, you can use the typed BeanFactory#getBean(Class requiredType, Object... args) method which looks up the bean by type.
This is at least true for Spring versions 4+.
Note that, if you don't want to start with the ApplicationContext or BeanFactory for your bean retrieval, you can inject an ObjectProvider (since Spring 4.3).
A variant of ObjectFactory designed specifically for injection points,
allowing for programmatic optionality and lenient not-unique handling.
and use its getObject(Object... args) method
Return an instance (possibly shared or independent) of the object
managed by this factory.
Allows for specifying explicit construction arguments, along the lines
of BeanFactory.getBean(String, Object).
For example,
#Autowired
private ObjectProvider<Thing> things;
[...]
Thing newThing = things.getObject(name);
[...]
With Spring > 4.0 and Java 8 you can do this more type-safely:
#Configuration
public class ServiceConfig {
#Bean
public Function<String, Thing> thingFactory() {
return name -> thing(name); // or this::thing
}
#Bean
#Scope(value = "prototype")
public Thing thing(String name) {
return new Thing(name);
}
}
Usage:
#Autowired
private Function<String, Thing> thingFactory;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = thingFactory.apply(name);
// ...
}
So now you can get your bean at runtime. This is a factory pattern of course, but you can save some time on writing specific class like ThingFactory (however you will have to write custom #FunctionalInterface to pass more than two parameters).
Since Spring 4.3, there is new way to do it, which was sewed for that issue.
ObjectProvider - It enables you just to add it as a dependency to your "argumented" Prototype scoped bean and to instantiate it using the argument.
Here is a simple example of how to use it:
#Configuration
public class MyConf {
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public MyPrototype createPrototype(String arg) {
return new MyPrototype(arg);
}
}
public class MyPrototype {
private String arg;
public MyPrototype(String arg) {
this.arg = arg;
}
public void action() {
System.out.println(arg);
}
}
#Component
public class UsingMyPrototype {
private ObjectProvider<MyPrototype> myPrototypeProvider;
#Autowired
public UsingMyPrototype(ObjectProvider<MyPrototype> myPrototypeProvider) {
this.myPrototypeProvider = myPrototypeProvider;
}
public void usePrototype() {
final MyPrototype myPrototype = myPrototypeProvider.getObject("hello");
myPrototype.action();
}
}
This will of course print hello string when calling usePrototype.
UPDATED per comment
First, I'm not sure why you say "this does not work" for something that works just fine in Spring 3.x. I suspect something must be wrong in your configuration somewhere.
This works:
-- Config File:
#Configuration
public class ServiceConfig {
// only here to demo execution order
private int count = 1;
#Bean
#Scope(value = "prototype")
public TransferService myFirstService(String param) {
System.out.println("value of count:" + count++);
return new TransferServiceImpl(aSingletonBean(), param);
}
#Bean
public AccountRepository aSingletonBean() {
System.out.println("value of count:" + count++);
return new InMemoryAccountRepository();
}
}
-- Test File to execute:
#Test
public void prototypeTest() {
// create the spring container using the ServiceConfig #Configuration class
ApplicationContext ctx = new AnnotationConfigApplicationContext(ServiceConfig.class);
Object singleton = ctx.getBean("aSingletonBean");
System.out.println(singleton.toString());
singleton = ctx.getBean("aSingletonBean");
System.out.println(singleton.toString());
TransferService transferService = ctx.getBean("myFirstService", "simulated Dynamic Parameter One");
System.out.println(transferService.toString());
transferService = ctx.getBean("myFirstService", "simulated Dynamic Parameter Two");
System.out.println(transferService.toString());
}
Using Spring 3.2.8 and Java 7, gives this output:
value of count:1
com.spring3demo.account.repository.InMemoryAccountRepository#4da8692d
com.spring3demo.account.repository.InMemoryAccountRepository#4da8692d
value of count:2
Using name value of: simulated Dynamic Parameter One
com.spring3demo.account.service.TransferServiceImpl#634d6f2c
value of count:3
Using name value of: simulated Dynamic Parameter Two
com.spring3demo.account.service.TransferServiceImpl#70bde4a2
So the 'Singleton' Bean is requested twice. However as we would expect, Spring only creates it once. The second time it sees that it has that bean and just returns the existing object. The constructor (#Bean method) is not invoked a second time. In deference to this, when the 'Prototype' Bean is requested from the same context object twice we see that the reference changes in the output AND that the constructor (#Bean method) IS invoked twice.
So then the question is how to inject a singleton into a prototype. The configuration class above shows how to do that too! You should pass all such references into the constructor. This will allow the created class to be a pure POJO as well as making the contained reference objects immutable as they should be. So the transfer service might look something like:
public class TransferServiceImpl implements TransferService {
private final String name;
private final AccountRepository accountRepository;
public TransferServiceImpl(AccountRepository accountRepository, String name) {
this.name = name;
// system out here is only because this is a dumb test usage
System.out.println("Using name value of: " + this.name);
this.accountRepository = accountRepository;
}
....
}
If you write Unit Tests you will be ever so happy you created the classes this without all the #Autowired. If you do need autowired components keep those local to the java config files.
This will call the method below in the BeanFactory. Note in the description how this is intended for your exact use case.
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* #param name the name of the bean to retrieve
* #param args arguments to use if creating a prototype using explicit arguments to a
* static factory method. It is invalid to use a non-null args value in any other case.
* #return an instance of the bean
* #throws NoSuchBeanDefinitionException if there is no such bean definition
* #throws BeanDefinitionStoreException if arguments have been given but
* the affected bean isn't a prototype
* #throws BeansException if the bean could not be created
* #since 2.5
*/
Object getBean(String name, Object... args) throws BeansException;
You can achieve a similar effect just by using an inner class:
#Component
class ThingFactory {
private final SomeBean someBean;
ThingFactory(SomeBean someBean) {
this.someBean = someBean;
}
Thing getInstance(String name) {
return new Thing(name);
}
class Thing {
private final String name;
Thing(String name) {
this.name = name;
}
void foo() {
System.out.format("My name is %s and I can " +
"access bean from outer class %s", name, someBean);
}
}
}
If you need to create a qualified bean you can do it this way:
#Configuration
public class ThingConfiguration {
#Bean
#Scope(SCOPE_PROTOTYPE)
public Thing simpleThing(String name) {
return new Thing(name);
}
#Bean
#Scope(SCOPE_PROTOTYPE)
public Thing specialThing(String name) {
Thing thing = new Thing(name);
// some special configuration
return thing;
}
}
// Usage
#Autowired
private ApplicationContext context;
AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
((DefaultListableBeanFactory) beanFactory).getBean("specialThing", Thing.class, "name");
Late answer with a slightly different approach.
That is a follow up of this recent question that refers this question itself.
Yes, as that was said you can declare the prototype bean that accepts a parameter in a #Configuration class that allows to create a new bean at each injection.
That will make this #Configuration class a factory and to not give this factory too much responsibilities, this should not include other beans.
#Configuration
public class ServiceFactory {
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Thing thing(String name) {
return new Thing(name);
}
}
But you can also inject that configuration bean to create Things :
#Autowired
private ServiceFactory serviceFactory;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = serviceFactory.thing(name); // create a new bean at each invocation
// ...
}
It is both type-safe and concise.
Nice solutions until now. But I want to post yet another alternative.
Spring has the #Lookup annotation. From javadoc:
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
you can declare your Thing as prototype bean:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Thing {
#Autowired
private SomeComponent someComponent;
#Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
}
then you can create instances by creating a method like createThing below in any other bean:
#Controller
public class MyController {
#Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = createThing(name);
//System.out.println(thing.getName()); //prints name
}
//or public. And can be put in any #Component (including #Configuration)
#Lookup
protected Thing createThing(String name) {
throw new UnsupportedOperationException("Method implemented by Spring.");
}
}
in your beans xml file use the attribute scope="prototype"
I've got a singleton Spring bean that creates a couple of tasks (java.util.concurrent.Callable's) at runtime to do its work in parallel. Right now, the Callable's are defined as inner classes in the singleton bean, and the singleton bean creates them simply by instantiating them with new Task(in), where in is a parameter known only at runtime.
Now I want to extract the inner Task class to a regular top-level class because I want to make the Task's call() method transactional, so I need it to be a Spring bean.
I guess I need to give my singleton some kind of factory of Tasks, but the tasks have to be prototype Spring beans that take a runtime value as a constructor parameter. How can I accomplish this?
Spring's bean factory and new are mutually exclusive. You can't call new and expect that object to be under Spring's control.
My suggestion is to inject those Tasks into the Singleton. Make them Spring beans, too.
You should recognize that the Task itself isn't going to be transaction, but its dependencies can be. Inject those into the Tasks and let Spring manage the transactions.
Another approach might be to use Spring's #Configurable annotation with load-time weaving, this way you can use new (instead of a bean factory) to create wired Callable's at runtime:
#Configurable
public class WiredTask implements Callable<Result> {
#Autowired
private TaskExecutor executor;
public WiredTask(String in) {
this.in = in;
}
public Result call() {
return executor.run(in);
}
}
#Bean #Scope("prototype")
public class TaskExecutor() {
#Transactional
public Result run(String in) {
...
}
}
// Example of how you might then use it in your singleton...
ExecutorService pool = Executors.newFixedThreadPool(3);
WiredTask task = new WiredTask("payload");
Future<Result> result = pool.submit(task);
See this article for more info. Note, you cannot use #Configurable and #Transactional in the same bean, hence the need for two classes. For that reason, this might not be the ideal solution if you have lots of different implementations of Callable (since you will need 2 classes for each one).
Your singleton bean can implement BeanFactoryAware and lookup beans from the containing spring factory.
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class MyBeanFactory implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
this.beanFactory = beanFactory;
}
public Task createTask(Task in) {
return beanFactory.getBean("task",in);
}
}
///////////////
import java.util.concurrent.Callable;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Scope;
import org.springframework.transaction.annotation.Transactional;
#Configurable // unless using xml based config
#Scope(value="prototype") // tell bean factory to create new instance each time
public class Task implements Callable<Object> {
private Object in;
public Task(Object in) {
super();
this.in = in;
}
#Transactional
public Object call() throws Exception {
//do real work
return in;
}
}
///