- 从企业级开发到云原生微服务:Spring Boot实战
- 汪云飞等
- 3464字
- 2021-04-04 11:26:51
3.2 Spring Bean的配置
3.2.1 注解配置(@Component)
当类注解为@Component、@Service、@Repository或@Controller时,Spring容器会自动扫描(通过@ComponentScan实现,Spring Boot已经做好了配置),并将它们注册成受容器管理的Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_46_02.jpg?sign=1739426504-gDb4O40BSjeBfyawKa5xMtLrtVa3C6Ty-0-faedd0d993972389bb35413f4895cf37)
@Component、@Service、@Repository和@Controller在当前示例中是完全等同的。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_46_03.jpg?sign=1739426504-oo1PthexrjVp1IC6RLi3ZF6ylNieIUqN-0-340a1610cbb3dba2036a809b6779e137)
上面的@Component和@Service都没有给Bean命名,Spring容器会自动命名为类名的第一个字母的小写形式,即someService和someService2。一般来说,没有必要去修改Bean的名称,使用默认的Bean名即可。当然,也可以通过@Component("SomeService")来设置Bean的名称。
@Service、@Repository和@Controller这三个注解组合了@Component注解,它们是@Component语义上的特例。
◎@Component:被注解类是“组件”。
◎@Controller:被注解类是“控制器”。
◎@Service:被注解类是“服务”。
◎@Repository:被注解类是“数据仓库”。
3.2.2 Java配置(@Configuration和@Bean)
在类上注解@Configuration(@Component的特例,会被容器自动扫描),可使类成为配置类。如果使用@Bean标注在类的方法上,则方法的返回值即为Bean的实例。假如现在有另外一个类。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_47_01.jpg?sign=1739426504-phaSEXQ5Z4smE8c580Uw4XPevtC0YKGu-0-5be80f9d223cba57aeda50db70492a6e)
用Java配置的如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_47_02.jpg?sign=1739426504-0aRz2qJt2HJovDDvOQVd7sIuSOJ9BRwm-0-c67735621c353a5ce2266ac2ecb14b7a)
同样,没有给Bean命名。Spring会将方法名anotherService默认成Bean的名称。若需要修改,则使用@Bean(name="AnotherService")。
3.2.3 依赖注入(Dependency Injection)
1.自动注入(@Autowired)
容器已经创建了SomeService、AnotherService和SomeService2的Bean,其他的Bean应如何注入使用呢?
(1)注解注入。
AnnotationInjectionService需要使用SomeService和AnotherService的Bean,我们只需在AnnotationInjectionService构造器上注解@Autowired,即可注入参数里需要的Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_47_03.jpg?sign=1739426504-8uhKqZFOf81VP7d9UhQGOp67Cd5RUAKS-0-cf8a020f546e82330507f002cccd0d6e)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_01.jpg?sign=1739426504-lcgnsVKlsAZkEAHdpEYsUeVhdFg9Udng-0-b7a67bd52f1f4ce911b76ac0ea9f65c9)
在构造器上注解注入是Spring推荐的注入方式,当然,也可以通过在属性上注解@Autowired来注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_02.jpg?sign=1739426504-fmqYYgkmojB7bmm1IS4NbcgpLhUgvvJC-0-bf844520eed08724b5174c49ebc4a018)
还可以在set方法上注解@Autowired来注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_03.jpg?sign=1739426504-v1GrV6BBBVh4OwTY0q2ILhXKPi1D6I3o-0-c7644afc0f41ab4d9702a7b652f7e4f6)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_01.jpg?sign=1739426504-ylBRvjsBJi5JgJDdE8EqpXaWGBrMv8hs-0-dbc35a8ee9b49f3f65fe168c88fd7902)
如果Bean只有一个构造器,则可以直接省略@Autowired注解。若Bean有多个构造器,则需注解一个构造器用来注入,示例如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_02.jpg?sign=1739426504-njBBnLWIfASAnMy4RgpK2P8jb4jmLsgZ-0-29c22afc4b39018e5aa50294ebbe42b0)
(2)配置注入。
现在使用Java配置的方式在Bean JavaConfigInjectService中注入BeanAnotherService,JavaConfigInjectService定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_03.jpg?sign=1739426504-Yd0jKs4gwK3IXMAMK5lAhfzYFB1ebtA2-0-278f0687305bcc774606ec5daad3bac1)
前面已经将AnotherService通过@Bean注解成Bean了,下面只需在定义JavaConfigInjectService的Bean的方法参数里注入AnotherService的Bean即可。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_04.jpg?sign=1739426504-ghyFmx6mVZUt7vMz2yDP74HQCPkFlqeg-0-5cbdab055d6df4c5a96f8f8b4b907a54)
在同一个配置类里,还可以在新建JavaConfigInjectService的构造里直接注入创建SomeService2的Bean的方法。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_05.jpg?sign=1739426504-b2NN7h5ZsoCESRmsJbG8kKELAdShS7cH-0-f576a24cd06c3f7fa4586488b22fa1ee)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_01.jpg?sign=1739426504-n89c4e8vmaM2bB2EekDPyybEV3ea6rCs-0-31877b3796701854a9d9232c905d0652)
(3)混合注入。
注解配置的Bean可以直接注入给使用Java配置的Bean,反之亦然。
把注解配置的Bean注入Java配置的Bean:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_02.jpg?sign=1739426504-dJQwwzteaiazdJikZsplTOP6j4Awa3do-0-20e1308d0ef7fc9db1af679f7a8d2e77)
把Java配置的Bean注入注解配置的Bean。被注入的BeanMixInjectionService2定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_03.jpg?sign=1739426504-VfHQCzVMnpGlwvLyo7WtxqpQzzPEosbk-0-6997f7148581a7e5f1e6530d02cc9b00)
在JavaConfig类里,可以直接在参数中注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_04.jpg?sign=1739426504-Pj4syZ2j5Ozyjo4GzxFKyVDBEhy1iIBu-0-75a845e13cacec14b01113c7cc9688bf)
2.@Primary
上面的例子都是通过Bean的名称来自动注入的。当Bean的名称不满足条件时,容器会根据Bean的类型进行自动注入。当全局只有一个类型的Bean时,自动注入是没有问题的,但是当全局有多个同类型的Bean时,会提示“required a single bean, but n were found”,此时可以通过@Primary来注解需要优先使用的Bean。假如有两个Bean:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_05.jpg?sign=1739426504-piOWgXAWTKD3WHz7hmGxzGCT6H1O8fBN-0-cc0cdf047c9bf51a92f31f0f76ae0e8e)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_51_01.jpg?sign=1739426504-4LKttm9J8FmBzt3Ve4yO13n7JkxHJJNv-0-57413e413c7747daff0b7517838eee15)
此时有两个Bean,名称分别为anotherService和primaryAnotherService。如果在注入的地方不使用这个两个名称,那么就会按照Bean的类型自动注入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_51_02.jpg?sign=1739426504-VYhihjGf98Ro7xKut38r5piuNBIWwJ84-0-b23b118a69fb6d48bd40715769d95b40)
因为现在使用的 service不符合按照名称自动注入,所以是按照类型自动注入的。因为primaryAnotherService注解了@Primary,所以使用primaryAnotherService这个Bean。
3.@Qualifier
在上面的例子中,使用UsePrimaryService注入的AnotherService的Bean只能是primaryAnotherService,这时可以使用@Qualifier直接指定需要使用哪个Bean。还是使用上面例子中的两个Bean。
注入anotherService:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_51_03.jpg?sign=1739426504-gewjyFurUGWX2tcWkbyAUsLmDq5aKIee-0-ebd830c2eb435296cf6e587dde67cbaa)
注入primaryAnotherService。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_52_01.jpg?sign=1739426504-BLp3d3uNWStRe65nAKDm2t6QRIzeP6bB-0-5536fd4d2f25237e8a5d9db683c5004f)
3.2.4 运行检验(CommandLineRunner)
在Spring Boot下可以注册一个CommandLineRunner的Bean,在容器启动后,这个Bean可用来执行一些专门的任务,如在JavaConfig里。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_52_02.jpg?sign=1739426504-09ByHDyWYPhJzVV1D0KajktG0E8j0cem-0-807d2cbfc85304c4f8885f014de9c9a6)
a.通过参数注入当前的CommandLineRunner Bean中。
b.CommandLineRunner是一个函数接口,输入的参数为main方法里接收的args参数。这里使用Lambda表达式执行每个Bean的doMyThing方法,如图3-1所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_53_01.jpg?sign=1739426504-zp8y34RVzAQJ3JpTG7UEGr80DJU9TCJ5-0-51c8406c49537fb4a61b04e1f1def045)
图3-1
CommandLineRunner有个姊妹接口叫作ApplicationRunner,它们之间唯一的区别是ApplicationRunner使用org.springframework.boot.DefaultApplicationArguments类型的参数,示例如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_53_02.jpg?sign=1739426504-bVWlFKvx4oJVSIEfZwVmraga4Cr2flWH-0-9adf722c23d59cc214081b04b3caa661)
CommandLineRunner的args是不定长字符串(String... args),而ApplicationRunner的args是DefaultApplicationArguments类型的对象。
3.2.5 Bean的Scope
容器中的Bean的Scope指的是Bean的实例在容器中创建的方式。在容器中,默认是singleton,即整个容器中只创建一个Bean的实例。常用的还有prototype,即每次请求Bean时都会创建一个实例。可以通过@Scope注解来设置Scope。
下面两种方式是相同的:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_53_03.jpg?sign=1739426504-w6Q17oq0VfCpKQdAuV0tJEPt6oYLu20O-0-8adb9d1f61c527bf379a9fbfce528870)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_01.jpg?sign=1739426504-WAY20tOijxa7wyAD9Xs8eLOLRsyFFRXb-0-a0dade1bb5eab861cac8101170b30027)
通过@Scope(BeanDefinition.SCOPE_PROTOTYPE)指定Scope为prototype:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_02.jpg?sign=1739426504-0UFHDOlJJvj16YMT0CX0RKZTQJCyZCEs-0-a5d7ad191645807b873a922dad5c7279)
除可以在方法上注解@Scope外,还可以在@Bean的类上注解@Scope,示例如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_03.jpg?sign=1739426504-PvoZbwACG4XuabeIbVHifrMnf97oFEca-0-25abbf60e50479e512ca9cf8c40361b9)
在JavaConfig中配置的代码如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_04.jpg?sign=1739426504-6qNkhkPshILSrSIDbmFL594polMecEsi-0-c60450cbba0c74e9e82c3775baf7d433)
这时可以在ScopeInjectService Bean中分别给上面三个Bean注入两次,由此判断相同类型的两个注入是否相等。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_05.jpg?sign=1739426504-Ec1mF9DreuuM55BFAOrPEEJzHCyMYIVW-0-ce095f8378c9c881b930a187dd7eedbb)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_01.jpg?sign=1739426504-7GhU1ml5P2CG8BuyqHge9r2A63m3oPQj-0-861413a4c02476c33a5c90c07ce3e10f)
在JavaConfig中配置下面的代码。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_02.jpg?sign=1739426504-SGSNWi330wwZ60c9nrlxaIYff8AzkClR-0-40827333a946d912fb63a3b7191c4ac3)
执行效果如图3-2所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_03.jpg?sign=1739426504-5IEEVxiinaCdrcktxZ0tUFBeis20qkBx-0-073778fe8abf95fc1c8174248d668812)
图3-2
3.2.6 Bean的生命周期
1.初始化和销毁
我们可以定制Bean在容器中的初始化行为和销毁行为。
(1)注解配置:使用@PostConstruct和@PreDestroy。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_04.jpg?sign=1739426504-sh1bX1wmeGC1zsicwuaRND2IwMovFfy4-0-67339f0b8e9a486a918fc9a036c9f3c4)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_01.jpg?sign=1739426504-EY7L2wJnsAbOwBqEFiSis7BdEOi89VPN-0-0f90d11ecb0715f60b6f5145f146b2c9)
执行效果如图3-3所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_02.jpg?sign=1739426504-sdlxfveFuCnwn8RURVwEkjuWDnh9YbK0-0-0e91c34e35ef71e3bf51cac82f18707c)
图3-3
(2)Java配置:使用@Bean的initMethod和destroyMethod。
Bean的定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_03.jpg?sign=1739426504-AzMMRoikk47YkUnnWS3L2whG97Z3rw47-0-277aa298f7fc2a0edd866dbba9801f2f)
在JavaConfig中配置下面的代码。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_04.jpg?sign=1739426504-BhKfXyKpSWmZ78XmlywKOuPVNiVcqzC1-0-304fed2aafa21cbf4b785722b798c77f)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_01.jpg?sign=1739426504-OQ1RiIw7CIOunvEXrGbpoG3wDfwL6l86-0-c02b086d661462fd588cab3ae97f7352)
执行效果如图3-4所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_02.jpg?sign=1739426504-oriYqSBm3oxbEUAgFoKtDhXrbNLS23Cx-0-b0f32323a32cc172fc74960eed291505)
图3-4
2.延迟初始化(@Lazy)
只要在Bean上注解了@Lazy,那么Bean在被调用时就会被初始化。它可以和@Component类注解或@Bean一起使用。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_03.jpg?sign=1739426504-bQYXcbJLoprl8V7M5rKZdVOHI3HzGgxB-0-9dd8ca67ec0737ef410c080de494c042)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_04.jpg?sign=1739426504-p70Cun0c9KbyfZkZ8VaN6UYom5NTweuJ-0-c88a99f0642e86c7fc63fca1c07ce892)
因为这两个Bean没有被调用过,所以没有被初始化,此时控制台没有任何输出。
3.依赖顺序(@DependsOn)
设置Bean lifeService2依赖于lifeService,让lifeService先初始化,可以用@DependsOn来实现。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_05.jpg?sign=1739426504-UrKMQ2j5B6untL4LS4tEf3lRL7xwSEdL-0-f61d0900ff487306bb03a44e50b5ce82)
执行的结果是lifeService先于lifeService2初始化,如图3-5所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_58_01.jpg?sign=1739426504-or76trLwy5lpJWc6YWRBzMqQKgUnltqa-0-9b6bf0a9bf91cc9139d2f6032e48d665)
图3-5
3.2.7 应用环境
Spring提供了一个接口Environment来代表当前运行的应用环境,这个环境包含两部分。
◎Profile:一组命名的、定义在一起的Bean。通常为不同的应用场景(生产环境、开发环境、测试环境等)定义。
◎Property:配置属性,可以从properties文件、JVM系统属性、操作系统环境变量等外部来获得配置属性。
1.场景(@Profile)
可以通过@Profile注解指定当前的运行场景。@Profile可以和@Component、@Configuration、@Bean等一起使用,当然也分别限制了@Profile生效的Bean的分组。
下面使用需要显示不同操作系统的列表命令(在Windows下为 dir,在Linux下为 ls)的Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_58_02.jpg?sign=1739426504-4yoti6brbw7HZkyUXLkcNsYOJx8vvodF-0-156935451a9830d2f6fcc54ea875b9ad)
在Windows开发环境下,场景配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_58_03.jpg?sign=1739426504-Qx7e9htUFE7fwFEO6v7pUoH6TI9Nzk8D-0-27f88c570375ffcd84c9875afec4d4e1)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_01.jpg?sign=1739426504-F7SmHmdPZPbN1Usov4HANnlmS31qhfZi-0-aaab0c2fd142c2826cca42db1ec11b8f)
在Linux开发环境下,场景配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_02.jpg?sign=1739426504-s3ZELv4TBY0CnEOcLHgI0zWFGXYoMdeV-0-4158249c6b2b9332f8f9d76cd659b5eb)
当配置好两种不同场景下的Profile后,我们需要在应用中配置哪个是激活的Profile,手动配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_03.jpg?sign=1739426504-Z8HlX37j5t2VGu3IhfzNOTiARGMDiitm-0-6b50dd226ee61e104247825b7de18287)
因为使用了Spring Boot,所以只需在application.properties文件中做如下配置即可。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_04.jpg?sign=1739426504-TuThHOmMqOUiEclmqnYyjbpqihsWmDpa-0-e4d694b8242e905ab9ce6e589671db6c)
在JavaConfig里,用CommandLineRunner分别将Profile配置成production和dev,执行效果如图3-6和图3-7所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_05.jpg?sign=1739426504-zXRNhUvJoteZ47lbHZD2eLGwDDGZq2Vd-0-c6a3e8adf39952029d2f518ed92b9f24)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_06.jpg?sign=1739426504-V8mrgnwlgGArlcL5ZuUvUKngL0R7gty5-0-7ae34d5b6423f342a6a4984381f4d3b7)
图3-6
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_07.jpg?sign=1739426504-XsYxTLjGzqWSklZkkBlITysNMjqYX2to-0-1199496ecd2ee6b9468c325ab4f87a78)
图3-7
2.属性配置(@PropertySource)
Spring的Environment属性是由PropertySource组成的,我们可以通过@PropertySource指定外部配置文件的路径。这些配置文件的属性都会以PropertySource的形式注册到Environment中,@PropertySource支持XML格式和properties格式,不支持Spring Boot下的YAML格式。
现在添加2个外部配置文件。
◎author.properties:
author.name=wyf
◎book.properties:
book.name=spring boot in battle
在添加完成后,可以用一个配置类来接收这两个文件的配置。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_60_01.jpg?sign=1739426504-FnfUfkvikraqVucrdKC2B7a1OjDSwrHi-0-d3de53925b70211b6c0f996edef71bb1)
a.当有多个外部配置时,可以用@PropertySources指定。若只有一个可用,则只使用@PropertySource("classpath:book.properties")。
b.注入Environment的Bean,因为只有一个构造器,所以可省略@Autowired。
c.可以通过@Value注解获得Environment中的属性,关于@Value的更详细的讲解见3.6节。
d.外部配置的属性都已经在Environment中注册过,可以直接获取。
3.2.8 条件配置(@Conditional)
通过@Conditional我们可以定义当满足某个特定条件(Condition)时,应该做什么配置。@Conditional同样可以和@Component、@Configuration、@Bean一起使用,进而指定条件起作用的范围。
@Conditional注解接收Condition数组作为参数,Condition即我们的特定条件。Condition只有一个方法matches,当符合条件时,返回true;当不符合条件时,返回false。
例如,判断当前系统是否是Windows的条件定义:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_61_01.jpg?sign=1739426504-JYiFcegHCNQp75nOpV2YPRSXeUry7QJM-0-4bb3cd41ea5c5e6577bee8641d1805bc)
a.条件实现Condition接口即可。
b.matches的两个参数:ConditionContext可获得容器的相关信息;AnnotatedTypeMetadata是当前被注解的方法或类的元数据(数据的描述)信息。
c.通过容器context获得运行环境Environment信息,从而获得操作系统信息。
配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_61_02.jpg?sign=1739426504-P0oH5udFwaRu4X0m2LG8HmKyFP1NbSg4-0-532a30ccbe4000f4cbb393cb3383fbc8)
a.@Conditional使用的是OnWindowsCondition条件,只有在操作系统是Windows的情况下,当前Bean才会被创建。
在JavaConfig中使用CommandLineRunner运行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_61_03.jpg?sign=1739426504-u1XYdPKcSowUzl1m3YmkV36RRdz8UYgW-0-9220aed2392f7cd94c4037b335fa3cdb)
在Windows系统才能正常执行;在非Windows系统下会报错,找不到Bean。因为不符合条件,所以没有创下这个Bean。
3.2.9 开启配置(@Enable*和@Import)
在本书后面的内容里会出现大量以@Enable*开头的注解,@Enable*会自动对相应的功能进行自动配置,如@EnableWebMvc、@EnableCaching、@EnableScheduling、@EnableAsync、@EnableWebSocket、@EnableJpaRepositories、@EnableTransactionManagement、@EnableJpaAuditing和@EnableAspectJAutoProxy等。
@Enable*的开启配置的功能依赖于@Import注解,@Import注解支持导入如下配置:
◎直接导入@Configuration配置类。
◎配置类选择器ImportSelector的实现。
◎动态注册器ImportBeanDefinitionRegistrar的实现。
◎混合以上三种。
下面将分别演示四种方式的实现。
1.直接导入@Configuration配置类
当应用注解了@Configuration后,会被Spring Boot的默认组件扫描并自动注册,所以本节的注解类代码放在 io.github.wiselyman.annotations中,配置类的代码放在io.github.wiselyman.config中。
定义注解:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_62_01.jpg?sign=1739426504-ruUSmcq8hxqcHbHIuI80bqj94y6IY8Z6-0-aa043238fc62e0d1aa6814ee734f9842)
定义配置类:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_62_02.jpg?sign=1739426504-Vh7GoRVU5DNH1r3aCOX9glKGqWKICjLx-0-f0e1deb435bfbe22dd3ab898e64eb658)
在JavaConfig中使用@EnableA注解,即可获得导入的配置类AConfig中的Bean a。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_01.jpg?sign=1739426504-nQmRptUqqLMqaamsSUqwQbEQZJGmEMtQ-0-1c7799c5990110a9e063fb3ee7836468)
在JavaConfig中使用CommandLineRunner查看Bean的内容,执行结果如图3-8所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_02.jpg?sign=1739426504-gTm1E3SwCkJJbzPEivHxvoznVj9o1461-0-d477431e7540d37dc9fef848d689e5c3)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_03.jpg?sign=1739426504-5F176MoA2YOPp7uGxO2NVv6EJUozKCta-0-9a7a3ff3e105890c669c119c8e51aa55)
图3-8
2.配置类选择器ImportSelector的实现
在这个例子中,通过注解选择生效的配置类,注解定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_04.jpg?sign=1739426504-TWyMibOFvyEKrce7PsDT5s2Y6oPvtbnU-0-71040a14b74e96b5d3d5b1119338559a)
在io.github.wiselyman.selector中定义选择器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_05.jpg?sign=1739426504-L188gZ6OtZapBHSg6dc2RYfwfxiKmwlW-0-d4a15b762967679227809aaa956fc7a6)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_01.jpg?sign=1739426504-ts2sSMNtL1D9TKU5cBl1WCCF2l5yuioE-0-69a1f470fb1fd03a92988bdfc7192b06)
a.选择器要实现ImportSelector接口。
b.实现接口的selectImports方法,参数AnnotationMetadata importClassMetadata是注解使用类(本例为JavaConfig)上@EnableB的元数据信息。
c.通过@EnableB在实际使用中的元数据,获得isUppercase的值。
d.如果isUppercase==true,则此时实际使用的是@EnableB或者@EnableB(isUppercase=true),因而使用BUppercaseConfig提供的配置。
e.若实际使用的是@EnableB(isUppercase=false),则使用BLowercaseConfig提供的配置。
BUppercaseConfig的定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_02.jpg?sign=1739426504-5hrFjtm2SGTGqbcrLst3dS70dXp4hyh2-0-9e37cdc631683b1b13495ce9ce74ab11)
BLowercaseConfig的定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_03.jpg?sign=1739426504-17VrsuFE1VJ9Dao44WzKMPFrCacTAuNN-0-ea7e980a554f255a16514289a7677112)
在JavaConfig中使用@EnableB,并用CommandLineRunner检验。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_04.jpg?sign=1739426504-i2E8aS6TmxzxMJ2Co2X52aMABgsEApJc-0-3d2aee093de3e02ef9a0c511b923d17b)
运行结果如图3-9所示。
若将isUppercase设置为false,则执行结果如图3-10所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_05.jpg?sign=1739426504-l5Q8Ghwh3EfFOCBI2A9WE4P2pg9C2k01-0-36555f60c5efaa827e41f85dfd329927)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_01.jpg?sign=1739426504-fEhaI1lVznsOMLPPlv2qgHpjD9NvmTZJ-0-30d376ab27366bb700a599531f8d84b7)
图3-9
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_02.jpg?sign=1739426504-MWmi0XqfUtOeQJ8lwg8GlFaF3s9Dk1B5-0-2add5fdda134a9c2ddcc06b57b189faf)
图3-10
3.动态注册器ImportBeanDefinitionRegistrar的实现
本例通过ImportBeanDefinitionRegistrar动态注册Bean到容器里。
注解定义如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_03.jpg?sign=1739426504-Q0eeFEPty8oDwV6zExyYcZ2GhyH6soKY-0-ac374ef5ce42f869559fdc5d8b312276)
在io.github.wiselyman.registrar中定义注册器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_04.jpg?sign=1739426504-pW8t0lWBpIedJ1nHx68l00cgy3skITkN-0-964cefefe4852be1e1b96eecfe449b0a)
a.注册器需实现ImportBeanDefinitionRegistrar接口。
b.实现registerBeanDefinitions参数AnnotationMetadata importClassMetadata是注解使用类(本例为JavaConfig)上@EnableB的元数据信息。
c.参数BeanDefinitionRegistry registry用来注册所有Bean的定义的接口。
d.可以使用BeanDefinitionBuilder来编程实现Bean的定义(BeanDefinition),此句定义了一个类型为String的Bean。
e.构造String的值是C。
f.设置Bean的Scope是singleton。
g.获得Bean的定义。
h.将Bean注册为名称为c的Bean。
此时,在JavaConfig上使用@EnableC注解,并用CommandLineRunner进行检验。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_01.jpg?sign=1739426504-jWDbkD3oY411Tt5iLFEQPxFeUuph2YUe-0-f39759e7de3c11dacb5a1741d5d03ad6)
IntelliJ IDEA可以检测到静态注册的Bean,但检测不到动态注册的Bean,因而IDE会标识红色,如图3-11中方框所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_02.jpg?sign=1739426504-IaOTk45Vm5iVBoA0qcfoOcPehkvykNJF-0-65fd56309b855162168b50fd0f3db07a)
图3-11
但可以正常运行,运行结果如图3-12所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_03.jpg?sign=1739426504-mq3Vq0bhOjaGzBK9FMWskVPgajzyd0ZG-0-7dab4d585ebe17300d37a15bcceec747)
图3-12
4.混合使用
@Import支持导入配置类的数组,因而我们可以混合上面三种配置,定义一个注解,使其具备上面三个功能。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_04.jpg?sign=1739426504-52TUwuJnQsbkPKCOYVc7o7F9eY5SkO2r-0-14a96d5c7867dac5ab4bc3c5a08d036a)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_01.jpg?sign=1739426504-9mjx77rjUWJttpFOMsKKz4Rf6cLeLOm3-0-6d344cedc13d9abfce54d7b372334eea)
因为选择器里指定了要使用的注解的类,所以需要新建一个选择器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_02.jpg?sign=1739426504-UHEwZwC0sdX2wNywa0AdiuOmn3miuMO1-0-8993310384f333b253726703dc03d45a)
在JavaConfig中启用@EnableABC,并用CommandLineRunner进行检验。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_03.jpg?sign=1739426504-jF93VHekda6AdtzLL4P7xIYDVWUmMBLb-0-271b2f416d835603190a62b4d0cdb398)
校验结果如图3-13所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_04.jpg?sign=1739426504-CQHmKL66xA4cMaN6YRhTc12GVkwSI5lD-0-2cd461e2168670d4e926f5c8c013a1e2)
图3-13