我正在处理一些现有的代码,而且它正在做我以前从未见过的事情。我使用方法注入或使用getBean()从上下文中获取bean,将原型bean自动装配到单例中。我在我正在处理的代码中看到的是一个bean,它是一个原型并使用getBean()检索,并且它具有自动连接的依赖项。其中大多数是单身豆,这是有道理的。但是有一个另一个原型bean的autowire,从我看到的,它看起来似乎正在获得一个新的bean。我的问题是当你将原型自动装配到原型中时,会给你一个新实例吗?由于autowire请求不是在启动时,而是在创建此bean时,是否会创建新实例?这违背了我对autowire和原型bean的看法,我希望能够从野外听到答案。感谢您的任何见解。我试图最小化我对这段代码的重构,因为它有点意大利面。
示例:
@Scope("prototype")
public class MyPrototypeClass {
@Autowired
private ReallyGoodSingletonService svc;
@Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
@Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
因此,当调用MyPrototypeClass中的doSomething()时,是" bean" MyPrototypeClass的每个实例的单例或新单元?
答案 0 :(得分:10)
在您的示例中,APrototypeBean
bean将被设置为一个全新的bean,它将一直存在,直到您创建的MyPrototypeClass
实例被销毁。
如果您创建了MyPrototypeClass
的第二个实例,那么该第二个实例将收到自己的APrototypeBean
。使用当前配置,每次调用doSomething()
时,都会在APrototypeBean
的{{1}}实例上调用该方法,该实例对于该MyPrototypeClass
对象是唯一的。
答案 1 :(得分:1)
您对@Autowired
或一般自动装配的理解存在缺陷。当创建bean的实例而不是在启动时发生自动装配。
如果你有一个懒惰的单例bean并且没有直接使用bean,那么只要在应用程序上下文中使用例如getBean
检索bean就不会发生任何事情。已创建,依赖关系已连线,BeanPostProcessors
已应用等。
对于每种类型的bean,只要在它之前创建它就会被处理,这是相同的。
现在回答你的问题,原型bean是一个原型bean,所以是的,每次调用getBean
时你都会收到新的实例。
答案 2 :(得分:0)
为@Mark Laren的回答添加更多解释。
中所述在大多数应用程序方案中,容器中的大多数bean都是 单身。当单例bean需要与另一个bean协作时 单例bean或非单例bean需要与之协作 另一个非单例bean,你通常通过处理依赖 将一个bean定义为另一个bean的属性。出现问题时 豆的生命周期是不同的。假设单身豆A需要 使用非单例(原型)bean B,可能在每个方法上 在A.上调用容器只创建一次单例bean A, 因此只有一次机会来设置属性。该 容器不能为bean A提供每个bean的新实例 需要时间。
下面的方法将解决这个问题,但这不是可取的,因为此代码将业务代码与Spring框架结合和违反 IOC模式。以下是此方法的示例:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
因此,有两种理想的方法可以解决这个问题。
<强> 1。使用Spring的方法注入
使用@Lookup。
来自Java Doc ...
表示“查找”的注释&#39;方法,被覆盖的方法 容器将它们重定向回BeanFactory以进行getBean调用。 这实际上是基于注释的XML版本 lookup-method属性,导致相同的运行时安排。
自: 4.1
@Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
@Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
上面的例子每次都会创建新的myClass2实例。
<强> 2。使用Java EE中的提供程序(Java的依赖注入(JSR 330))。
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Component
public static class SomeRequest {}
@Service
public static class SomeService {
@Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
以上示例每次都会创建新的SomeRequest实例。