Spring@autowired是否不适用于非单例容器?

Spring@autowired是否不适用于非单例容器?,spring,singleton,spring-aop,autowired,Spring,Singleton,Spring Aop,Autowired,我有一个MyTask类,它实现了Runnable,并且可以在任何给定时刻实例化许多这样的对象。我想将某些属性自动关联到MyTask类中 但是我认为如果我用@Component标记MyTask,那么它将成为一个spring管理的单例,对吗?这不是我想要的,我需要这个类的许多独立实例由TaskExecutor运行 因此,我的问题是: a) 我对@组件注释的理解是否根本错误?它不是把MyTask变成了spring管理的单例吗 b) 是否应该使用其他注释,以便spring检测@Autowired并注入

我有一个
MyTask
类,它实现了
Runnable
,并且可以在任何给定时刻实例化许多这样的对象。我想将某些属性自动关联到
MyTask
类中

但是我认为如果我用
@Component
标记
MyTask
,那么它将成为一个spring管理的单例,对吗?这不是我想要的,我需要这个类的许多独立实例由TaskExecutor运行

因此,我的问题是:

  • a) 我对
    @组件
    注释的理解是否根本错误?它不是把
    MyTask
    变成了spring管理的单例吗
  • b) 是否应该使用其他注释,以便spring检测
    @Autowired
    并注入属性
  • c) spring autowiring是否不适用于非单例容器/类,如
    MyTask

更新#1-这些不起作用:

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
    }
}


更新#2-在等待更多关于如何以简单方式完成此操作的建议时,我正在研究:
使用AspectJ依赖注入域对象,Spring
作为替代。

在使用上下文进行类路径扫描时,@Component注释允许它们自动检测:Component scan 它就是这样做的。@Service和@Component之间有一条细线,在这种情况下,它无论如何都不会产生影响

Spring自动布线可以用于原型和单例范围。对于原型作用域,不调用用于销毁bean的生命周期回调

Spring文档页面对此进行了很好的解释。

我看不出你提到的任何东西都不起作用的原因

他是我试图更好地解释它的一个工作样本

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

   }
}
这是应用程序的起点

这是你的myTask课程

@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;
   }

}
另外两个类显示原型作用域是如何工作的

@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;
   }

}
一个BeanPostprocessor,它将向您展示如何创建对象

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;
   }
}
你的SomeSpringConfig类

@Service
public class SomeSpecialSpringConfiguredConnectionClass {

   private String value = "someValue";

   public String getValue() {
      return value;
   }

   public void setValue(final String value) {
      this.value = value;
   }

}
运行此示例时,您会注意到控制台上的输出是

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
如果您注意到有两个具有不同哈希代码的myTask对象

如果您将myTask的作用域更改为“Singleton”,这里将显示输出

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
在本例中,为“myTask”创建了一个对象


这有帮助吗?

首先,用@Component声明并由spring组件扫描拾取的bean在默认情况下将成为spring管理的单例

我不知道您是如何使用MyTask的,但是在您的情况下使用AspectJ是有点过头了,而且将MyTask声明为spring管理的bean也没有多大意义。另一种方法是:

  • 将MyTask定义为普通java类,并添加构造函数来初始化依赖项
    blah

  • autowire blah,您可以在其中使用
    MyTask
    ,并在每次执行任务时实例化MyTask对象,如下所示:

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

  • 不要使用@Autowire,而是使用@Inject,看看它的神奇之处。
    我有同样的情况,在这里,验证器类是Java单例类,而不是spring范围的bean。我需要注入另一个团队提供的UAA客户端Springbean。因此@Autowire不起作用,但@Inject起作用。

    通常添加@Scope(“prototype”)不会导致autowired blah bean出现空错误,您应该检查如何实例化MyTask bean。 我认为问题在于您手动实例化MyTask,如:

       MyTask task = new MyTask();
    
    因此,它不受Spring的控制,这就是为什么它的依赖项BlahBean为null,而不是手动实例化,您需要自动连接它,让Spring处理它的依赖项,然后blah将不会为null。 但还有另一个问题。在另一个单例对象中自动连接原型bean MyTask是错误的。Spring容器只创建一个单例bean一次,因此只设置一次原型bean,这导致原型范围不起作用。如下所示,Myactivity是一个单例,它自动连接MyTask,我还为MyTask添加了一个构造函数,以便在创建MyTask的新实例后打印一些内容。在下面的例子中,它只打印一次,所以原型不工作

    @Component
    @Scope("prototype")
    public class MyTask implements Runnable {
    
      @Autowired
      public SomeSpecialSpringConfiguredConnectionClass blah;
    
      public MyTask(){
        System.out.println("New Instance of MyTask");
      }
    
      @Override
      public void run() {
        assert(blah != null);
      }
    }
    
    
    @Component
    public class MyActivity {
    
      @Autowired
      private MyTask task;
    
      public MyTask start() {
        return task;
      }
    }
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = {MyActivity.class, MyTask.class, 
       SomeSpecialSpringConfiguredConnectionClass.class})
    public class MyTaskTest {
    
      @Autowired
      private MyActivity activity;
    
      @Test
      public void testActivity() {
        for (int i = 0; i < 5; i++) {
            MyTask task = activity.start();
            task.run();
        }
      }
     }
    
    现在原型工作正常,这是控制台中打印的结果:

    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    

    您可以指定Springbean的作用域。如果您将它标记为原型(而不是默认的sigleton),那么每次都会得到新的实例。您可以通过在class-level@Scope(“prototype”)上添加此注释将该类标记为原型,谢谢!但这不符合我的要求,我已经试过了。你打算如何使用我的任务?你说的不适用于@Scope(“原型”)是什么意思?不知道为什么更改范围不起作用。除非您可能将依赖项注入MyTask到另一个单例中,否则在这种情况下,您可能需要研究方法注入或AOP。请看一下@Septem——在更新1中详细阐述,以解释我所说的
    与@Scope(“原型”)不起作用的意思。
    感谢Septem,我一直在使用这种方法,并想开始一个Q,看看我是否可以或不能远离它。同意过度杀戮的部分。。。这正是为什么我将我的问题措辞为:
    Spring@autowired是否不适用于非单例容器?
    我接受这个答案,因为它基本上说:
    不,autowired不适用于非单例容器
    我的问题。。。至于我是如何让代码工作的,我使用
    AspectJ将Spring
    作为替代方案注入依赖域对象。感谢Hrishikesh,挑战在于如果在
    MyTask
    run()
    方法中打印
    someSpringObject
    。。。您将看到这两个原型对象都为null。。。这就是我想要解决的问题。
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask