2014-09-30 35 views
1

我正在使用一些现有的代码,它正在做我以前没见过的事情。我已经使用方法注入将原型bean自动装入单例,或者使用getBean()从上下文获取bean。我在这段代码中看到的是一个bean,它是一个原型并使用getBean()进行检索,并且它具有自动装配的依赖关系。其中大部分是单身豆,这是有道理的。但是有另一个原型bean的自动装载,从我看来,它看起来好像正在获得一个新的bean。我的问题是,当你将原型自动装入原型时,是否会给你一个新的实例?由于autowire请求不是在启动时创建的,而是在创建这个bean的时候,它是否会创建一个新的实例?这违背了我对autowire和prototype beans的看法,我想听到外面的答案。感谢您的任何见解。我试图尽量减少对代码的重构,因为它有点意大利面条。将原型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() { 
    } 
} 

所以当DoSomething的()在MyPrototypeClass叫,是“豆”一个单身或MyPrototypeClass的每个实例一个新的?

回答

10

在你的例子中,APrototypeBean bean将被设置为一个全新的bean,它将一直存在,直到你创建的MyPrototypeClass的实例被销毁。

如果您创建MyPrototypeClass的第二个实例,那么第二个实例将收到它自己的APrototypeBean。使用您当前的配置,每当您拨打doSomething()时,该方法将在APrototypeBean的实例上调用,该实例对该MyPrototypeClass对象是唯一的。

+0

好的解释@马克拉伦 – 2016-06-30 15:05:22

1

您对@Autowired或自动装配的了解通常是有缺陷的。自动装配在创建bean的实例时发生,而不是在启动时发生。

如果您将有一个懒惰的单例bean,并且没有直接使用bean,只要您在应用程序上下文中使用例如getBean来检索bean,就会创建一个实例,依赖关系会得到连接,BeanPostProcessors得到应用等。

这是每一个类型的豆,它将被处理,只要它不是在此之前创建它是相同的。

现在要回答你的问题,一个原型bean是一个原型bean,所以是的,你会收到新的实例,每次调用getBean

+0

谢谢 - 所以我明白,使用getBean检索bean会为您提供一个新实例。这就是原型的定义。但是在这个bean的内部,如果有一个原型范围bean的自动装载,那么它是否也创建了该bean的新实例?这是我以前从未见过的。 – titania424 2014-10-01 14:55:45

+0

为什么不应该。正如我在创建bean时所说明的那样,它注入了它的依赖关系,这些依赖关系也是使用'getBean'检索的,所以同样适用。我想我的答案已经很清楚了。创建时刻也是注入,代理创建等时刻,应用程序上下文不关心的范围。 – 2014-10-01 17:32:53

0

向@Mark Laren的答案添加更多解释。

Spring 4.1.6 docs

说明在大多数应用场景,最豆在容器是 单身。当一个单例bean需要与另一个单例bean协作时,或者一个非单例bean需要与另一个非单例bean协作时,通常需要将依赖关系定义为 ,将一个bean定义为另一个bean的属性。当豆类生命周期不同时,会出现问题 。假设单例bean A需要 使用非单例(原型)bean B,也许在每个方法 上调用A.容器只创建一个单例bean A, ,因此只有一次机会来设置属性。 容器无法向bean A提供一个新的bean B实例,每 需要一次。

下方接近将解决这个问题,但这不是理想因为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; 
    } 
} 

所以,有2个理想的方法来解决这个问题。

1.使用Spring的方法注入

  • 正如名字所暗示的,Spring将实施&如果您使用XML版本使用@Lookup注释从春4或标记注入我们的抽象方法。请参阅this DZone article

通过使用@Lookup。

从Java文档...

的注释,表示“查找”的方法,由 容器覆盖,以他们重定向回Bean工厂的电话的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实例。

相关问题