I have a MyTask
class which implements Runnable
and there can be many such objects instantiated at any given moment. There are certain properties that I would like to autowire into MyTask
class.
But I think that if I mark MyTask
with @Component
then it will become a spring-managed singleton correct? That's not what I want, I need many independent instances of this class to be run by a TaskExecutor.
So my question(s):
@Component
annotation? Does it NOT make MyTask
into a spring-managed singleton?@Autowired
and injects the property?MyTask
?Update # 1 - These don't work:
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// BLAH IS NULL, this shouldn't be NULL, that is not what I want
// which makes sense considering Spring never knew it had to work
// on this class
}
}
@Component
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// this works BUT now MyTask is singleton :(
}
}
@Component
@Scope("prototype")
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// BLAH IS NULL, again ... this shouldn't be NULL, that is not what I want
}
}
Update # 2 - While waiting for some more suggestions on how to do it the easy way, I'm looking into: Using AspectJ to dependency inject domain objects with Spring
as an alternative.
You can simply put @Autowired annotation, followed by visibility tag and object, to can use every object managed by Spring context. But beware, all of these objects are a kind of Spring-managed singleton.
If you autowire a singleton bean, Spring looks for an existing instance inside the application context and provides it to you. If you autowire the bean in multiple places, Spring will still provide you with the same instance. When you autowire a prototype bean, Spring will initialize a new instance of the bean.
The @Autowired annotation provides more fine-grained control over where and how autowiring should be accomplished. The @Autowired annotation can be used to autowire bean on the setter method just like @Required annotation, constructor, a property or methods with arbitrary names and/or multiple arguments.
Spring Certification Question: Which of the following is true regarding the @Autowired annotation? Select Your Answer: A: It is possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type.
first, beans declared with @Component and picked up by spring component scan will become a spring-managed singleton by default.
I have no idea how you use MyTask, but it is overkilled to use AspectJ in your situation, and it does not make much sense to declare MyTask as a spring-managed bean. another way of doing this will be:
define MyTask as a plain java class and add a constructor to initialize the dependency blah
autowire blah in where you use MyTask
, and instantiate a MyTask object every time you want to execute a task as follow:
//autowire the dependency of MyTask in another spring bean with default singleton scope
@Autowired private SomeSpecialSpringConfiguredConnectionClass blah
//create task and wire the blah yourself
executor.submit(new MyTask(blah))
The @Component annotation would allow them for auto detetion while classpath scanning using the context:component scan That is what it does. there is a fine line between @Service and @Component, and in this case it does not affect in anyway.
Spring autowiring can be done for prototype as well as singleton scopes. In case of the prototype scope though the lifecycle callbacks for the destruction of the bean isnt called.
It is explained very well on the Spring documentation page. http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
I dont see a reason why whatever mentioned by you shouldnt work.
He is a working sample of what i tried to do to explain it better.
public class SpringContainerStartClass {
public static void main(final String[] args) {
final ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext("beans.xml");
final MainApplication1 bean = (MainApplication1) bf.getBean("mainApplication1");
bean.getMyTask().printSomething();
}
}
This is the starting point of the app.
Here is your myTask class
@Component(value = "myTask")
@Scope(value = "prototype")
public class MyTask
implements Runnable {
@Autowired
private SomeSpecialSpringConfiguredConnectionClass someSpringObject;
@Override
public void run() {
System.out.println("running now");
}
public void printSomething() {
System.out.println(someSpringObject.getValue());
}
public SomeSpecialSpringConfiguredConnectionClass getSomeSpringObject() {
return someSpringObject;
}
public void setSomeSpringObject(final SomeSpecialSpringConfiguredConnectionClass someSpringObject) {
this.someSpringObject = someSpringObject;
}
}
Two other classes to show how the prototype scope is working
@Component
public class MainApplication1 {
@Autowired
private MyTask myTask;
public MyTask getMyTask() {
return myTask;
}
public void setMyTask(final MyTask myTask) {
this.myTask = myTask;
}
}
@Component
public class MainApplication2 {
@Autowired
private MyTask myTask;
public MyTask getMyTask() {
return myTask;
}
public void setMyTask(final MyTask myTask) {
this.myTask = myTask;
}
}
A BeanPostprocessor which will show you how the objects are getting created
public class InstantiationTracingBeanPostProcessor
implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}
your SomeSpringConfig class
@Service
public class SomeSpecialSpringConfiguredConnectionClass {
private String value = "someValue";
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}
When you run this sample, you will notice that the output on the console is
INFO: Loading XML bean definitions from class path resource [beans.xml]
Jan 02, 2014 12:07:15 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@26efabf8: defining beans [mainApplication1,mainApplication2,myTask,someSpecialSpringConfiguredConnectionClass,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,com.stackoverflow.DIQuestion.InstantiationTracingBeanPostProcessor#0,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Bean 'someSpecialSpringConfiguredConnectionClass' created : com.stackoverflow.DIQuestion.SomeSpecialSpringConfiguredConnectionClass@1e20d04b
Bean 'myTask' created : com.stackoverflow.DIQuestion.MyTask@175d6331
Bean 'mainApplication1' created : com.stackoverflow.DIQuestion.MainApplication1@741b31f2
Bean 'myTask' created : com.stackoverflow.DIQuestion.MyTask@2c2815d3
Bean 'mainApplication2' created : com.stackoverflow.DIQuestion.MainApplication2@7bb0e64a
If you notice carefulyy there are 2 objects of myTask with different hashcodes.
If you change the scope of the myTask to "Singleton" here would be the output.
INFO: Loading XML bean definitions from class path resource [beans.xml]
Jan 02, 2014 12:08:35 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@26efabf8: defining beans [mainApplication1,mainApplication2,myTask,someSpecialSpringConfiguredConnectionClass,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,com.stackoverflow.DIQuestion.InstantiationTracingBeanPostProcessor#0,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Bean 'someSpecialSpringConfiguredConnectionClass' created : com.stackoverflow.DIQuestion.SomeSpecialSpringConfiguredConnectionClass@1e20d04b
Bean 'myTask' created : com.stackoverflow.DIQuestion.MyTask@175d6331
Bean 'mainApplication1' created : com.stackoverflow.DIQuestion.MainApplication1@741b31f2
Bean 'mainApplication2' created : com.stackoverflow.DIQuestion.MainApplication2@2c2815d3
In this case there is one object created for "myTask"
Does this help?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With