@Import注册非组件bean



我注意到,即使没有用@Component注释的类在@Import注释中声明时也会注册到Spring上下文中。

@Configuration
@Import({MyBean.class})
class MyConfig {
@Bean
Object object(MyBean myBean) { // this works
return new Object();
}
}
class MyBean {} // no annotation here

这种行为在@Import文档中并不十分清楚。

这是需要的吗?它有记录吗?导入非@component类和@Component类之间有什么区别吗?

文件上写着:

允许导入@Configuration类、ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规组件类

什么是"常规组件类"?有类或用@Component注释的类吗?

摘要

@Import注释旨在将引用的类转换为bean定义。如果一个";常规的";组件是用@Import导入的,通常没有理由用@Component对其进行注释,因为此注释不会为生成的bean指定任何类型的行为。@Component不主要将类标记为Springbean,而是将类标记为由类路径扫描拾取的类。

通常,导入的类是用@Configuration注释的配置类。配置类也将作为bean包含在最终的应用程序上下文中。单词";常规的";在此上下文中,指的是而非的bean(或组件),以及将其他bean定义添加到应用程序上下文中的配置类或其他类型的bean。单词";常规的";这里也可以用例如";正常的";或";普通香草";。

事实上,使用@Import导入的配置类也不需要使用@Configuration进行注释。但在这种情况下,由于来自@Bean注释工厂方法的bean将在";bean-lite";如果注释CCD_ 15丢失。

详细信息

注释@Component不描述作为注释类实例的bean的任何类型的行为。它实际上只是一个类的标记。如果使用类路径扫描来配置应用程序上下文,那么任何用@Component注释的类都将被转换为bean定义,该bean定义将生成作为注释类实例的bean。

这在注释的javadoc中也有说明:

表示带注释的类是一个";部件";。当使用基于注释的配置和类路径扫描时,这些类被认为是自动检测的候选者。

如今,基于注释的配置和类路径扫描是配置Spring应用程序上下文的主要方式。这在过去是不正确的,例如也看到了大量的XML配置。事实上,Spring框架比Java5更早,Java5是第一个向该语言引入注释的Java。

如果使用基于注释的配置,但而不是类路径扫描,则注释@Import允许创建从中央配置类到其他配置类的引用,或者特别是";常规的";组件类。这也是参考文档中关于这个功能的描述:

从Spring Framework 4.2开始,@Import还支持对常规组件类的引用,类似于AnnotationConfigApplicationContext.register方法。如果您想通过使用一些配置类作为入口点来显式定义所有组件,从而避免组件扫描,这一点尤其有用。

因此,如果不使用类路径扫描,那么用@Component标记类基本上没有意义,因为它没有规定任何行为。这不仅适用于";常规的";使用@Import导入的bean,但也适用于来自XML配置中<bean>元素的bean或功能注册的bean。

在Spring4.2之前,注释@Import只能导入非常规bean,例如@Configuration类。这是因为@Import可以被认为是XML配置中<import>元素的等价物,该元素用于包括例如其他XML文件,这些文件随后再次包含<bean>元素。

单词";常规的";在本文中,指的是如果使用类路径扫描,我通常会用@Component注释的类。该词在这里仅用于区分这样的类与"类";非规则的";组件,如@Configuration类、ImportSelector和ImportBeanDefinitionRegistrar实现。

它在java文档中声明使用ImportResource导入不是@Configuration的类

如果需要导入XML或其他非@Configurationbean定义资源,请改用@ImportResource注释。

虽然这可能是"作品":

@Configuration
@Import({MyBean.class})
class MyConfig {
@Bean
Object object(MyBean myBean) { // this works
return new Object();
}
}
class MyBean {} // no annotation here

这个(bean)不会(除非spring能够"解析参数"):

package io.external;
//no spring annotations
public class MyBean {
public MyBean(String gotcha) { // ! ...
// just a demo
}
} 

上下文将无法从以下内容开始:

APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in io.external.MyBean required a bean of type 'java.lang.String' that could not be found.

Action:
Consider defining a bean of type 'java.lang.String' in your configuration.

By";常规组件类";spring文档必须引用带注释的类

  • @Component
  • @Repository(@NoRepositoryBean!;)
  • @Service
  • 甚至@Configuration(,@SpringBootApplication,@TestConfiguration(?),…)<-@Import的最典型和记录
  • 以及他们的后代/继承人

。。。正如beans构造型注释所描述的那样。


另一方面,当我们尝试不使用@Import({MyBean.class})时,它也会失败,原因是:

Parameter 0 of method object in com.example.... required a bean of type 'io.external.MyBean' that could not be found.

以上观察结果和进一步的测试(使用弹簧不可解析构造函数)使我得出结论:

  • @Import(MyBean.class)(在"非组件类"上)的行为与@Bean MyBean myBean(...) { return new MyBean(...)}的行为相同
  • 而CCD_ 41的实例化是由CCD_。。。(目前)因此:
    • 当CCD_ 43具有(即;默认构造函数";,这将被使用
    • 否则,当存在:
      • 没有唯一的构造函数,No default constructor found解析/实例化失败
      • 一个唯一的(非默认的)构造函数,spring将尝试解析(自动连接)构造函数参数。。。有两种可能的结果(成功与否)

请尝试不同的构造函数组合(&order):

package io.external;
public class MyBean {
//public MyBean(String gotcha) {
//    System.err.println("a");
//}
public MyBean(org.springframework.core.env.Environment fIoc) {
System.err.println("b");
}
//public MyBean() { // <- this will pass!
//    System.err.println("c");
//}
}

有关详细信息和当前文档,请参阅:

  • https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-工厂级
  • https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-工厂属性详细信息

最新更新