我注意到,即使没有用@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-工厂属性详细信息