无论如何,@Autowire需要构造函数参数的bean?

我正在使用Spring 3.0.5,并尽可能为我的类成员使用@Autowire注释。 我需要自动assembly的一个bean需要参数给它的构造函数。 我已经浏览了Spring文档,但似乎无法find如何注释构造函数参数的任何参考。

在XML中,我可以使用它作为bean定义的一部分。 有@Autowire注释类似的机制?

例如:

@Component public class MyConstructorClass{ String var; public MyConstructorClass( String constrArg ){ this.var = var; } ... } @Service public class MyBeanService{ @Autowired MyConstructorClass myConstructorClass; .... } 

在这个例子中,我如何使用@Autowire注解在MyBeanService中指定“constrArg”的值? 有没有办法做到这一点?

谢谢,

埃里克

您需要@Value注释。

常见的用例是使用"#{systemProperties.myProp}"样式expression式来指定默认的字段值。

 public class SimpleMovieLister { private MovieFinder movieFinder; private String defaultLocale; @Autowired public void configure(MovieFinder movieFinder, @Value("#{ systemProperties['user.region'] }"} String defaultLocale) { this.movieFinder = movieFinder; this.defaultLocale = defaultLocale; } // ... } 

请参阅: expression式语言>注释configuration


更清楚的是:在你的场景中,你需要连接两个类MybeanServiceMyConstructorClass ,像这样:

 @Component public class MyBeanService implements BeanService{ @Autowired public MybeanService(MyConstructorClass foo){ // do something with foo } } @Component public class MyConstructorClass{ public MyConstructorClass(@Value("#{some expression here}") String value){ // do something with value } } 

更新:如果您需要使用不同值的MyConstructorClass几个不同的实例,您应该使用限定符注释

在这个例子中,我如何使用@Autowire注解在MyBeanService指定“constrArg”的值? 有没有办法做到这一点?

不,不是你的意思。 代表MyConstructorClass的bean必须是可configuration的,而不需要任何客户端bean,所以MyBeanServiceMyConstructorClass的configuration方式上没有MyBeanService的说法。

这不是一个自动assembly的问题,这里的问题是Spring如何实例化MyConstructorClass ,假设MyConstructorClass是一个@Component (并且您正在使用组件扫描,因此不在您的configuration中明确指定MyConstructorClass )。

正如@Sean所说,这里的一个答案是在构造函数参数上使用@Value ,以便Spring从系统属性或属性文件中获取构造函数的值。 另一种方法是让MyBeanService直接实例化MyConstructorClass ,但是如果你这样做,那么MyConstructorClass就不再是一个Spring bean。

那么,我不时遇到同样的问题。 据我所知,当一个想要添加dynamic参数给构造函数的人不能这样做。 但是,工厂模式可能会有所帮助。

 public interface MyBean { // here be my fancy stuff } public interface MyBeanFactory { public MyBean getMyBean(/* bean parameters */); } @Component public class MyBeanFactoryImpl implements MyBeanFactory { @Autowired WhateverIWantToInject somethingInjected; public MyBean getMyBean(/* params */) { return new MyBeanImpl(/* params */); } private class MyBeanImpl implements MyBean { public MyBeanImpl(/* params */) { // let's do whatever one has to } } } @Component public class MyConsumerClass { @Autowired private MyBeanFactory beanFactory; public void myMethod() { // here one has to prepare the parameters MyBean bean = beanFactory.getMyBean(/* params */); } } 

现在, MyBean本身不是一个春豆,但它已经足够接近了。 dependency injection的工作,虽然我注入的工厂,而不是豆本身 – 一个人必须注入一个新的工厂之上,他自己的新的MyBean实现,如果要replace它。

此外, MyBean可以访问其他bean – 因为它可能访问工厂的自动assembly东西。

有人可能显然想要添加一些逻辑到getMyBean函数,这是我允许的额外的努力,但不幸的是我没有更好的解决scheme。 由于问题通常是dynamic参数来自外部来源,例如数据库或用户交互,所以我只能在中途运行时才能实例化这个bean,只有当这些信息可用时, Factory应该是足够的。

您需要使用@Autowired和@Value。 请参阅这篇文章了解更多关于这个主题的信息

另一种方法是将parameter passing给你可能把它们作为getter和setter的构造函数,然后在@PostConstruct中根据需要初始化这些值。 在这种情况下,Spring将使用默认的构造函数创buildbean。 下面是一个例子

 @Component public class MyConstructorClass{ String var; public void setVar(String var){ this.var = var; } public void getVar(){ return var; } @PostConstruct public void init(){ setVar("var"); } ... } @Service public class MyBeanService{ //field autowiring @Autowired MyConstructorClass myConstructorClass; .... } 

大多数答案都是相当老的,所以当时可能还没有可能,但实际上有一个解决scheme可以满足所有可能的用例。

所以知道答案是:

  • 不提供真正的Spring组件(工厂devise)
  • 或不适合每一种情况(使用@Value你必须有一个configuration文件中的值的地方)

解决这些问题的解决scheme是使用ApplicationContext手动创build对象:

 @Component public class MyConstructorClass { String var; public MyConstructorClass() {} public MyConstructorClass(String constrArg) { this.var = var; } } @Service public class MyBeanService implements ApplicationContextAware { private static ApplicationContext applicationContext; MyConstructorClass myConstructorClass; public MyBeanService() { // Creating the object manually MyConstructorClass myObject = new MyConstructorClass("hello world"); // Initializing the object as a Spring component AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory(); factory.autowireBean(myObject); factory.initializeBean(myObject, myObject.getClass().getSimpleName()); } @Override public void setApplicationContext(ApplicationContext context) throws BeansException { applicationContext = context; } } 

这是个很酷的解决scheme,因为:

  • 它使您可以访问对象上的所有Springfunction(显然@Autowired ,也可以@Async ),
  • 你可以使用你的构造函数参数(configuration文件,计算值,硬编码值等)的任何来源,
  • 它只需要你添加几行代码而不需要改变任何东西。
  • 它也可以用来dynamic地创build一个Springpipe理类的未知数量的实例(例如,我正在使用它来创build多个asynchronous执行器)

唯一要记住的是,你必须有一个构造函数,在你想要实例化的类中(或者如果你需要的话可以使用@Autowired构造函数)不带任何参数(可以是空的)。

你也可以像这样configuration你的组件:

 package mypackage; import org.springframework.context.annotation.Configuration; @Configuration public class MyConstructorClassConfig { } @Bean public MyConstructorClass myConstructorClass(){ return new myConstructorClass("foobar"); } } 

Bean注解,你告诉Spring在BeanFactory注册返回的bean。

所以你可以自动assembly它,如你所愿。