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) 我对
注释的理解是否根本错误?它不是把@组件
变成了spring管理的单例吗MyTask
- 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也没有多大意义。另一种方法是:
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