Spring在手动类实例化期间注入@Autowired字段

时间:2018-12-12 06:21:18

标签: java spring

在我的项目中,我惊讶地发现即使是手动实例化了类,Spring(4.3)仍试图自动关联类的依赖关系。

MyClass.java(注意龙目岛注释):

@NoArgsConstructor
@AllArgsConstructor
public class MyClass {
    @Autowired
    private MyClassDependency dependency;
}

MyClassDependency.java使用工厂方法并且没有Spring注释:

public class MyClassDependency {
    public static MyClassDependency create() { return new MyClassDependency(); }
}

Spring配置产生NoSuchBeanDefinitionException

@Configuration
public class SpringConfig {
    @Bean
    public MyClass myClass() {
        return new MyClass(MyClassDependency.create());
    }
}

提供bean使Spring高兴:

@Configuration
public class SpringConfig {
    @Bean
    public MyClass myClass() {
        return new MyClass(); // let autowire inject dependencies
    }
    @Bean
    public MyClassDependency myClassDependency() {
        return MyClassDependency.create();
    }
}

这对我来说是一个很大的惊喜。我想要配置的第一个简单版本...此行为来自/受控制的地方在哪里? (可能是我错过了它或将其从某些依赖项中删除了。)

PS:为澄清起见,MyClass代码不在我的控制范围内,但是我可以更改Spring配置。我想了解Spring如何通过bean方法拦截构造函数调用,以及是否可以代替使用构造函数。

6 个答案:

答案 0 :(得分:2)

如本old Stack Overflow thread所述,这是一种骇人听闻的方法。

public static <T> FactoryBean<T> preventAutowire(T bean) {
    return new FactoryBean<T>() {
        public T getObject() throws Exception {
            return bean;
        }

        public Class<?> getObjectType() {
            return bean.getClass();
        }

        public boolean isSingleton() {
            return true;
        }
    };
}

...

@Bean
static FactoryBean<MyBean> myBean() {
    return preventAutowire(new MyBean());
}

答案 1 :(得分:2)

让我们进一步澄清一下Celebi指出的答案。

您对它的行为感到惊讶似乎源于将布线行为的一部分向后看,而不是其工作原理。

您写道:

  

..我很惊讶地看到Spring(4.3)似乎试图自动接线   类的依赖关系,即使手动实例化也是如此。

如果没有@Bean表示法,则不要尝试连接非bean的“ MyClassDependency”类。实际上,从Spring的角度来看,它根本没有“看到”该类。

代码的另一面是询问类名称为“ MyClassDependency”的bean-这就是开始尝试查找“ MyClassDependency”并创建连接的原因。当然,它找不到该名称/条件的任何匹配bean。

您的问题似乎更多地是关于需要理解为什么它以您观察到的方式运行,我相信这就是原因。

从功能上讲,您可能已经解决了自己的问题。通过在MyClassDependency之上添加@Bean,对于Spring,您现在可以使用一个可见的Bean,供其他请求它的代码使用。

答案 2 :(得分:1)

问题如下:

  1. 您用@Autowired注释了一个字段-告诉Spring,有一个依赖项需要注入那里
  2. 您使用@Bean注释了一个方法-该方法将返回值放入Spring的上下文中。
  3. 当Spring处理@Bean注释对象的返回值时,它开始进行其注释-并且存在一个带有注释的字段,该字段告诉Spring在该字段中注入依赖项,即使该字段已经具有值分配。
  4. Spring尝试在此处注入依赖项,但是该依赖项在Spring上下文中不存在,因此注入失败。

因此,拥有@Bean但手动注入@Autowired依赖项会相互冲突,您现在可能会明白,为什么-您不能手动注入Autowired Bean! Autowired是一个注释,告诉他CI容器进行一些注入工作。

答案 3 :(得分:0)

在此示例中,您应使用StateSelector

AbstractFactoryBean

答案 4 :(得分:0)

该行为来自@Bean注释definition

  

1.12.1。基本概念:@Bean和@Configuration

     

Spring的新Java配置支持中的主要工件是@Configuration注释的类和@Bean注释的方法。

     

@Bean批注用于指示方法实例化,配置和初始化要由Spring IoC容器管理的新对象。对于熟悉Spring的<beans/> XML配置的用户来说,@ Bean注释与<bean/>元素具有相同的作用。您可以将@Bean批注方法与任何Spring @Component一起使用。但是,它们最常与@Configuration bean一起使用。

preventAutowire proposed by Fabio Manzano是可以接受的解决方法,直到another solution is provided by Spring

答案 5 :(得分:0)

Spring将覆盖您提供的MyClassDependency的实例。因为您将MyClass定义为具有自动关联的bean。您要告诉Spring进行管理,而Spring会按照您的要求进行操作。

您绝对可以通过用@Autowired注释构造函数来使用构造函数注入,但是如果您无权访问MyClass的源代码,那就没问题了。

这是您无需更改MyClass的源代码或不熟悉Spring bean生命周期即可获得的最简单的配置。

如果您想了解bean的生命周期,可以参考IoC Container documentation