Java 如何避免在春季使用applicationContext.getBean?

Java 如何避免在春季使用applicationContext.getBean?,java,spring,dependency-injection,Java,Spring,Dependency Injection,我有一个类条实现如下: class Bar implements ApplicationContextAware { ApplicationContext applicationContext; void barFoo() { final Foo foo = applicationContext.getBean(Foo.class); foo.doSomeWork(); foo.shutDownProperly(); }

我有一个类实现如下:

class Bar implements ApplicationContextAware {

    ApplicationContext applicationContext;

    void barFoo() {
        final Foo foo = applicationContext.getBean(Foo.class);
        foo.doSomeWork();
        foo.shutDownProperly();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
<bean id="foo" class="biz.tugay.Foo" scope="prototype"/>
foo在我的配置中定义如下:

class Bar implements ApplicationContextAware {

    ApplicationContext applicationContext;

    void barFoo() {
        final Foo foo = applicationContext.getBean(Foo.class);
        foo.doSomeWork();
        foo.shutDownProperly();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
<bean id="foo" class="biz.tugay.Foo" scope="prototype"/>

因为,Singleton Foo无法正确完成工作,每次都必须正确关闭

我认为
getBean
打破了整个“依赖注入”/“可测试”原则


但是对于“barFoo”方法,我如何将“原型Foo”注入“Bar”中?

您可以使用org.springframework.beans.factory.ObjectFactory:

class Bar {

@Autowired
private ObjectFactory<Foo> fooObjectFactory;

}

您可以使用org.springframework.beans.factory.ObjectFactory:

class Bar {

@Autowired
private ObjectFactory<Foo> fooObjectFactory;

}

所以您需要在单例bean中注入原型bean,并在单例方法的每次调用中使用原型bean的新版本

您可以尝试使用ScopedProxyFactoryBean,但是Spring框架参考手册建议使用查找方法注入

您的
Bar
课程将成为:

class Bar implements ApplicationContextAware {

    ApplicationContext applicationContext;

    void barFoo() {
        final Foo foo = createFoo();
        foo.doSomeWork();
        foo.shutDownProperly();
    }

    protected abstract Foo createFoo(); // Implementation will be provided by Spring Framework
}
您只需在bean定义中声明方法:

<bean id="foo" class="biz.tugay.Foo" scope="prototype"/>
<bean id="bar" class="biz.tugay.Bar">
    <lookup-method name="createFoo" bean="command"/>
</bean>

参考文献(重点):

具有原型bean依赖项的单例bean
..
但是,假设您希望单例作用域bean获取原型作用域的新实例 bean在运行时重复运行。您不能将依赖项注入原型范围的bean singleton bean,因为当Spring容器实例化 SingletonBean及其依赖项的解析和注入如果您需要原型的新实例 bean多次运行,请参阅名为“方法注入”的部分

查找方法注入

查找方法注入是容器重写容器管理bean上的方法的能力, 返回容器中另一个命名bean的查找结果。查找通常涉及 原型bean[…]。Spring框架实现了 该方法通过使用CGLIB库中的字节码生成来动态生成 重写该方法的子类


所以您需要在单例bean中注入原型bean,并在单例方法的每次调用中使用原型bean的新版本

您可以尝试使用ScopedProxyFactoryBean,但是Spring框架参考手册建议使用查找方法注入

您的
Bar
课程将成为:

class Bar implements ApplicationContextAware {

    ApplicationContext applicationContext;

    void barFoo() {
        final Foo foo = createFoo();
        foo.doSomeWork();
        foo.shutDownProperly();
    }

    protected abstract Foo createFoo(); // Implementation will be provided by Spring Framework
}
您只需在bean定义中声明方法:

<bean id="foo" class="biz.tugay.Foo" scope="prototype"/>
<bean id="bar" class="biz.tugay.Bar">
    <lookup-method name="createFoo" bean="command"/>
</bean>

参考文献(重点):

具有原型bean依赖项的单例bean
..
但是,假设您希望单例作用域bean获取原型作用域的新实例 bean在运行时重复运行。您不能将依赖项注入原型范围的bean singleton bean,因为当Spring容器实例化 SingletonBean及其依赖项的解析和注入如果您需要原型的新实例 bean多次运行,请参阅名为“方法注入”的部分

查找方法注入

查找方法注入是容器重写容器管理bean上的方法的能力, 返回容器中另一个命名bean的查找结果。查找通常涉及 原型bean[…]。Spring框架实现了 该方法通过使用CGLIB库中的字节码生成来动态生成 重写该方法的子类


取决于上下文,但您可能希望使用原型bean而不是singleton@NickVanderhovenFoo已经是原型了,但是Bar本身是单例的。这取决于上下文,但是您可能希望使用原型bean而不是singleton@NickVanderhovenFoo已经是原型了,但Bar本身是单例的。ObjectFactory的所有实现似乎都是私有内部类,而Autowired似乎不起作用。ObjectFactory的所有实现似乎都是私有内部类,而Autowired似乎不起作用。