Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Spring @autowired not meant for non-singleton containers?

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):

  • a) Am I fundamentally wrong in my understanding of @Component annotation? Does it NOT make MyTask into a spring-managed singleton?
  • b) Is there some other annotation I should use so that spring detects @Autowired and injects the property?
  • c) Is spring autowiring not meant for non-singleton containers/classes like 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.

like image 953
pulkitsinghal Avatar asked Jan 01 '14 21:01

pulkitsinghal


People also ask

Are Autowired objects singleton?

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.

Does Autowire create 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.

What is use of @autowired in Spring?

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.

Which of the following statement is correct about @autowired annotation?

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.


2 Answers

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:

  1. define MyTask as a plain java class and add a constructor to initialize the dependency blah

  2. 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))
    
like image 50
Septem Avatar answered Sep 21 '22 04:09

Septem


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?

like image 41
Hrishikesh Avatar answered Sep 24 '22 04:09

Hrishikesh