【问题标题】:How to inject dependencies into a self-instantiated object in Spring?如何将依赖项注入到 Spring 中的自实例化对象中?
【发布时间】:2011-04-18 08:01:47
【问题描述】:

假设我们有一个类:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

然后我们创建了这个类的一个对象(或者其他一些框架已经创建了这个类的实例)。

MyClass obj = new MyClass();

是否仍然可以注入依赖项?比如:

applicationContext.injectDependencies(obj);

(我认为 Google Guice 有这样的东西)

【问题讨论】:

    标签: java spring dependency-injection


    【解决方案1】:

    我使用了不同的方法。我有弹簧加载的 bean,我想从创建自己的线程的第三方库的扩展类中调用它们。

    我使用了我在这里找到的方法https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs

    在非托管类中:

    {
        [...]
        SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
    
        [...]
        bc.someMethod(...)
    }
    

    然后作为主应用程序中的辅助类:

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SpringContext implements ApplicationContextAware
    {
        private static ApplicationContext context;
    
        public static <T extends Object> T getBean(Class<T> beanClass)
        {   
            return context.getBean(beanClass);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext context) throws BeansException
        {   
            SpringContext.context = context;
        }
    }
    

    【讨论】:

    • 这对我来说是在进入汇合链接后工作的。已投赞成票。
    【解决方案2】:

    我想与@glaz666 answer 中提到的briefly 分享我遵循@Configurable 方法的解决方案,因为

    • @skaffman 的 answer 已有近 10 年的历史,这并不意味着不够好或不起作用
    • @glaz666 的回答很简短,并没有真正帮助我解决问题,但确实为我指明了正确的方向

    我的设置

    1. 带有Spring Neo4j &amp; Aop starts 的Spring Boot 2.0.3(无论如何都无关紧要)
    2. Spring Boot 准备好时使用@Configurable 方法(使用ApplicationRunner)实例化一个bean
    3. Gradle 和 Eclipse

    步骤

    我需要按照以下步骤才能使其正常工作

    1. @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) 将放置在您的 Bean 之上,该 Bean 将被手动实例化。在我的情况下,要手动实例化的 Bean 具有 @Autowired 服务,因此是上述注释的道具。
    2. @EnableSpringConfigured@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)注释Spring Boot的主要XXXApplicaiton.java(或带有@SpringBootApplication注释的文件)
    3. 在构建文件中添加依赖项(即 build.gradle 或 pom.xml,具体取决于您使用的那个)compile('org.springframework.boot:spring-boot-starter-aop')compile('org.springframework:spring-aspects:5.0.7.RELEASE')
    4. 新建+up Bean,在任何地方都用@Configurable 注释,并且它的依赖关系应该是自动装配的。

    *关于上面的第 3 点,我知道org.springframework.boot:spring-boot-starter-aop 传递性地拉动spring-aop(如此处所示mavencentral)但是,在我的情况下,Eclipse 未能解决@EnableSpringConfigured 注释因此,为什么我除了启动器之外还明确添加了spring-aop 依赖项。如果您遇到同样的问题,只需声明依赖关系或继续冒险去弄清楚

    • 是否存在版本冲突
    • 为什么org.springframework.context.annotation.aspect.* 不可用
    • 您的 IDE 设置是否正确
    • 等等等等

    【讨论】:

      【解决方案3】:

      刚刚得到了同样的需求,在我的例子中,它已经是非 Spring 可管理的 java 类中的逻辑,它可以访问 ApplicationContext。灵感来自Scaffman。 解决者:

      AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
      factory.autowireBean(manuallyCreatedInstance);
      

      【讨论】:

        【解决方案4】:

        你也可以用@Configurable注解来标记你的MyClass:

        @Configurable
        public class MyClass {
           @Autowired private AnotherClass instance
        }
        

        然后在创建时它会自动注入其依赖项。您还应该在应用程序上下文 xml 中包含 &lt;context:spring-configured/&gt;

        【讨论】:

        • Galz666,你的方法看起来更干净,适合我想做的事情。但是我无法让它工作。我没有 xml 文件,并且完全使用 Java 配置。有没有等价于&lt;context:spring-configured/&gt; 的?
        • 这是一个干净的解决方案,但需要更多的努力:您应该使用加载时编织,如 iimuhin 上面所示,或者将 AspectJ 编译器添加到项目中。顾名思义,加载时间会导致运行时的额外成本。
        【解决方案5】:

        您可以使用AutowireCapableBeanFactoryautowireBean() 方法来执行此操作。你向它传递一个任意对象,Spring 会将它视为它自己创建的东西,并将应用各种自动装配的点点滴滴。

        要获取AutowireCapableBeanFactory,只需自动连接:

        private @Autowired AutowireCapableBeanFactory beanFactory;
        
        public void doStuff() {
           MyBean obj = new MyBean();
           beanFactory.autowireBean(obj);
           // obj will now have its dependencies autowired.
        }
        

        【讨论】:

        • 好答案 (+1)。还有第二种方法可以影响自动装配的发生方式:static.springsource.org/spring/docs/3.0.x/javadoc-api/org/…
        • 但是如果我有两个对象,第一个自动装配第二个。案例中autowire bean factory如何处理依赖关系?
        • 这实际上是一个糟糕的模式。如果这就是您真正使用 MyBean 的方式,为什么不使用以 AnotherBean 作为参数的构造函数。类似于:code private @Autowired AnotherBean bean; public void doStuff() { MyBean obj = new MyBean(bean); }code。似乎与所有这些注释一样,人们真的很困惑,只是不使用从第一天开始就在 java SDK 中的基本模式。:(
        • 我同意 - Spring 重新定义了整个语言。现在,我们将接口用作具体类,将方法用作类实例,并使用各种复杂且代码繁重的方法来完成您过去在新的和体面的设计中所做的事情。
        • @Denis 如果 MyBean 具有实际类不需要的依赖项,则您正在注册实际不存在的依赖项,只是为了实例化一个类,所以实际上没有区别。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-10-05
        • 1970-01-01
        • 2012-02-26
        • 1970-01-01
        • 1970-01-01
        • 2016-11-29
        • 2019-06-24
        相关资源
        最近更新 更多