![从企业级开发到云原生微服务:Spring Boot实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/257/33831257/b_33831257.jpg)
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=1739625685-G8O0PCCBo117LIkoEhmUYqUeroOPu5BC-0-ed907a0b94cdc15b8ed895dabe59aaa8)
@Component、@Service、@Repository和@Controller在当前示例中是完全等同的。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_46_03.jpg?sign=1739625685-GhUz7ofO3Mvr8Fqge33ph0NSuhzMpg7P-0-3db0e48d5d0fbc9ad75fb4eed56eaa36)
上面的@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=1739625685-ibPTP2219eSxuwuNp581aLg5RAkdDxQW-0-84a435e9cbcc0220c46b7baad200461b)
用Java配置的如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_47_02.jpg?sign=1739625685-KiDL6eDErElDbmHNQJS6H3gXUUin4Vn3-0-c1101b6d8c0e7e6e6fc2de0f27447355)
同样,没有给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=1739625685-lqhNerIeThxk8MojlhSWN5GPDSp9dAP3-0-3503ace29f2045736227d007b2c8af2a)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_01.jpg?sign=1739625685-KCf54nlNDdV5TKRFf6WjdCDztznaIRzY-0-2d59ee508d95f61dafa1f2b8c25b0f5c)
在构造器上注解注入是Spring推荐的注入方式,当然,也可以通过在属性上注解@Autowired来注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_02.jpg?sign=1739625685-TX6b14K0W67nCsKNIcGOpBkANkS8e4gs-0-a76af0075f5b6bb4bcc9e58ccebff6e6)
还可以在set方法上注解@Autowired来注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_48_03.jpg?sign=1739625685-wY2DtGPTqlJUb01urWPnMWRSr7IxjSn3-0-e5759b26ccaa189e42cad763a1a563e5)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_01.jpg?sign=1739625685-mQ4HR57O5xqoU3j6KcQnPAEx4QvRTjZD-0-f45effa203e3bd8488799949091f0f24)
如果Bean只有一个构造器,则可以直接省略@Autowired注解。若Bean有多个构造器,则需注解一个构造器用来注入,示例如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_02.jpg?sign=1739625685-vRDIjusHYjUp2OTjQi2GAPpO4knxQEBB-0-09118dea245615cd39e3b8337eef866f)
(2)配置注入。
现在使用Java配置的方式在Bean JavaConfigInjectService中注入BeanAnotherService,JavaConfigInjectService定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_03.jpg?sign=1739625685-7jM3NNpwavpOjJ1wjAVfLGiTdnixrSFa-0-52668fecb86de0459e79d80d10b009c1)
前面已经将AnotherService通过@Bean注解成Bean了,下面只需在定义JavaConfigInjectService的Bean的方法参数里注入AnotherService的Bean即可。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_04.jpg?sign=1739625685-Es0c86UxDiHB35jiXC0OAIb1HsNOZ79W-0-a9c8d29b639207610aa03d341949b355)
在同一个配置类里,还可以在新建JavaConfigInjectService的构造里直接注入创建SomeService2的Bean的方法。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_49_05.jpg?sign=1739625685-ueelnS9r79V9LyjdP8medAHBdzxE6x3x-0-d1d14c4ed03cb430c657f863d3ee4a3e)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_01.jpg?sign=1739625685-wC0UNOsNuzFIWXKAh1PgHSJ8yYX3fxfk-0-1cd8d87f59e10c7e7e0d67fe1166314d)
(3)混合注入。
注解配置的Bean可以直接注入给使用Java配置的Bean,反之亦然。
把注解配置的Bean注入Java配置的Bean:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_02.jpg?sign=1739625685-ebEo7s4Le6RwwJTFpZRDq0hPxnog0rJp-0-82f9bce06ffd0d66f900d9a3ad8143cd)
把Java配置的Bean注入注解配置的Bean。被注入的BeanMixInjectionService2定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_03.jpg?sign=1739625685-kXqNER4q4UrfQlHUa1OutXnU3AE3MSgZ-0-9ad41a131ad2807fea95eec67f4b10c5)
在JavaConfig类里,可以直接在参数中注入Bean。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_50_04.jpg?sign=1739625685-cCRpcvHseLsbwOcgNKOTzIERwqNg7xKu-0-17ac1878cb0c1cfd9965674529d6b64f)
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=1739625685-pAluojP7oI3850B0ZkDzvGYelgM7Ic3x-0-aa110d2b2c97c5770b22b111d1d32b49)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_51_01.jpg?sign=1739625685-LAPzu0CGCCU0RXka7a3YUiJ6ol0dEmlE-0-870aca03a2a45bcda0a9180201634412)
此时有两个Bean,名称分别为anotherService和primaryAnotherService。如果在注入的地方不使用这个两个名称,那么就会按照Bean的类型自动注入。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_51_02.jpg?sign=1739625685-tBC6EfXBg94AvBiErzoXU7fJVqzrzZOE-0-cfb008c8dfd5c9d5b922abc5c72a1b51)
因为现在使用的 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=1739625685-Rd8WDGUQ60NjrLQSMEuoeWTPJ6tJJhta-0-3a352b9ad7a0b8dd7dada26817b2a218)
注入primaryAnotherService。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_52_01.jpg?sign=1739625685-4uIv5ZdRe5TZdnxFDI7xSPSbAmOo5NiT-0-7506086a1c78850392bb24893df74668)
3.2.4 运行检验(CommandLineRunner)
在Spring Boot下可以注册一个CommandLineRunner的Bean,在容器启动后,这个Bean可用来执行一些专门的任务,如在JavaConfig里。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_52_02.jpg?sign=1739625685-TqOMPqZM0EBMb2djrcJEQNZZFwwPta6G-0-4222d6547d3731b7baef08976d730ac0)
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=1739625685-50uV76KtdO8AdFSsZOqVtL3R082PCbJa-0-02af02a62df5d45dfd6e1500b143f0f7)
图3-1
CommandLineRunner有个姊妹接口叫作ApplicationRunner,它们之间唯一的区别是ApplicationRunner使用org.springframework.boot.DefaultApplicationArguments类型的参数,示例如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_53_02.jpg?sign=1739625685-ghzZVEUQjOnq8Wfev2oqpdIAeBK4jwA5-0-ce7d973befe79062ad39dc450665f46f)
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=1739625685-UCGr7sbAHUHeZHuk7DXOz1plufe2nmrB-0-aa34dcaa1d5fea200fbe3234294b40a0)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_01.jpg?sign=1739625685-cW3VJNN4REi2ZF8iXGIcnudmZXJhyXFa-0-1455fdd8246f8389c2e4de13883ceba4)
通过@Scope(BeanDefinition.SCOPE_PROTOTYPE)指定Scope为prototype:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_02.jpg?sign=1739625685-XfroXWJQHpVt5A1aJfpcIB8DRS3fs7Bx-0-8a6393b04f7e75873440bb7d3defb8ce)
除可以在方法上注解@Scope外,还可以在@Bean的类上注解@Scope,示例如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_03.jpg?sign=1739625685-y3Yivmm3Ma1c9no14SXIoybrjCge5q2j-0-5a1355e5f9a280ce324a50490b2f2402)
在JavaConfig中配置的代码如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_04.jpg?sign=1739625685-IVwLH61R3s4TqUQJ4xpNjIggciWxuy5l-0-108d06d71dfe645374c67b26bfdb19df)
这时可以在ScopeInjectService Bean中分别给上面三个Bean注入两次,由此判断相同类型的两个注入是否相等。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_54_05.jpg?sign=1739625685-H5NR24oNH1uuvvdWtyJp5CM40g63Z4Yf-0-c7ab73e7730af7b7681de87e166d61e0)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_01.jpg?sign=1739625685-SQhi1tt6UqmigaeukK5LJG3l9PSXPe8Z-0-62b769c729a0faa1332b43b6aed3f93b)
在JavaConfig中配置下面的代码。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_02.jpg?sign=1739625685-rR9jyf3LwsvBi9uZc3fZGe09zuyP2Hmh-0-29a7e1517ab8948a06f3aeb4865d35f1)
执行效果如图3-2所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_55_03.jpg?sign=1739625685-vz8Xcxnq0YHFq0ohhSGTi35SPqI4rRyJ-0-1bee793dad4463e323e3e52fc3397518)
图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=1739625685-8W6xzxj0cn6QL89ehDCTusnjAJnYnsm4-0-4b4a438b98a744f198cb233dc1db44bc)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_01.jpg?sign=1739625685-LNmPYnRZX66GR72h6a36EvnC5Lfq5j9F-0-f6b47f54fa9a35f041dd9b9933370e7a)
执行效果如图3-3所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_02.jpg?sign=1739625685-PnH9IMrneKtKsqV2fc6sLuBj4Bdw6fJX-0-3cfcc7eda817267933ab5a97ab00960c)
图3-3
(2)Java配置:使用@Bean的initMethod和destroyMethod。
Bean的定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_03.jpg?sign=1739625685-Zo1ZKkesQ0tv7OLHt1vPb40lOxMH7sHr-0-85ce59bf341490142b665ff4412d8644)
在JavaConfig中配置下面的代码。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_56_04.jpg?sign=1739625685-XpCfn96DZcVwgzmkaZXCwGGPTHcpWXgO-0-4caca0822de09ed03cce1866ddaca6cb)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_01.jpg?sign=1739625685-wol4lB8czZjcP1KPrnHAY08PTbQY8VQo-0-b8afab35f5d7bd5de72d0a6c80c12297)
执行效果如图3-4所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_02.jpg?sign=1739625685-GORuKjSyHgqzAgoYjX2zry2ozgnyLrdT-0-b11b980592b1032446c0b849c934a282)
图3-4
2.延迟初始化(@Lazy)
只要在Bean上注解了@Lazy,那么Bean在被调用时就会被初始化。它可以和@Component类注解或@Bean一起使用。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_03.jpg?sign=1739625685-7NB95AvNEm70q0pKwrBE8J63cU34Ttd5-0-5fda2402ee07497be1382bca6dbf72ff)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_04.jpg?sign=1739625685-ERp7p6XvaotIMhDBCeyPEcAx7IY5Js2W-0-7ed1a5b43b4127edfabdc9b523fc87e2)
因为这两个Bean没有被调用过,所以没有被初始化,此时控制台没有任何输出。
3.依赖顺序(@DependsOn)
设置Bean lifeService2依赖于lifeService,让lifeService先初始化,可以用@DependsOn来实现。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_57_05.jpg?sign=1739625685-msVRTs8iGsueRmJmdMDikyNDqfPfz06A-0-a9893135b532f286256eeb8a086677d9)
执行的结果是lifeService先于lifeService2初始化,如图3-5所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_58_01.jpg?sign=1739625685-lZwRFOxqP4erj6sJLtOntQwBZ0QKyEqv-0-b166f8c6402afb67feba9e4e885502c8)
图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=1739625685-sb6BHl7OCkiMbgeFaFJv51yoi9l6I2Bk-0-9af72e9766589c48ba2855366cb053ee)
在Windows开发环境下,场景配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_58_03.jpg?sign=1739625685-EXyf6xXyYK5Svhx4T0Z6brlO1CQm6uA0-0-01406b604aa560528a29eabc4ce8af45)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_01.jpg?sign=1739625685-r9qvo0Rur8CTtGU5SMZA24tDjWJvr1X0-0-c67ab11a8f6b09f0268c3c895a98d756)
在Linux开发环境下,场景配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_02.jpg?sign=1739625685-qRGCBa8f7tV0YNkzUS0mmstcOprvB3f7-0-d0aa97322388267a7c50dcb118d8c4e2)
当配置好两种不同场景下的Profile后,我们需要在应用中配置哪个是激活的Profile,手动配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_03.jpg?sign=1739625685-EUu3qhT8D46O3hPowzodnz9d3fOQ8lw5-0-214ec77febcb80af308813ef457ef83f)
因为使用了Spring Boot,所以只需在application.properties文件中做如下配置即可。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_04.jpg?sign=1739625685-cIzx30uOZ5ZGTirrVX61kULqteDn2m8L-0-ff86466ac59d79e8b644bf70faa62653)
在JavaConfig里,用CommandLineRunner分别将Profile配置成production和dev,执行效果如图3-6和图3-7所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_05.jpg?sign=1739625685-X0A2xI2N6b6fyoq583L609ymBymumdpK-0-3d220328d6db1b2ceaf69db4fb738563)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_06.jpg?sign=1739625685-LlnaoUjYkffY0bIpBzZeiiwS0mgEmioD-0-d67d63e0dc381aa1d37d27341daea0c1)
图3-6
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_59_07.jpg?sign=1739625685-Jmhs6S9wzaJrhy8RFnPyYhxFSANZVUNY-0-37e63f55bd5e51028d8e188b1d4cc030)
图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=1739625685-ki4eebe0GmZHkgQC6uP2gHuh7mpSgjZ3-0-51aad0ce724301f9570fd652886df490)
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=1739625685-IDLi2ESJlyiJ3qGwIvFToYrR9Jleu61E-0-b00e473ef5bac7db2737f3c279a2d39f)
a.条件实现Condition接口即可。
b.matches的两个参数:ConditionContext可获得容器的相关信息;AnnotatedTypeMetadata是当前被注解的方法或类的元数据(数据的描述)信息。
c.通过容器context获得运行环境Environment信息,从而获得操作系统信息。
配置如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_61_02.jpg?sign=1739625685-BA25ClRGmbNZcnHy0cSt1LRX7E795Yk5-0-4187a5e92e575478a0df36b5242ae20a)
a.@Conditional使用的是OnWindowsCondition条件,只有在操作系统是Windows的情况下,当前Bean才会被创建。
在JavaConfig中使用CommandLineRunner运行。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_61_03.jpg?sign=1739625685-sCz37G0D5UEMHSlvIOdykRyxLjqRCToi-0-81873d0e0945757e7ce635a22a55b86f)
在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=1739625685-TRNuVObwtBnuZNzziCN4tOmIItJkm75c-0-ffe4ba1679665c778e909d84e6b5bf12)
定义配置类:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_62_02.jpg?sign=1739625685-krF8wBIgY470DcPQoiGEytiSG24NGbrq-0-bf78b49e6d42a54f494ab7aeb91e9b39)
在JavaConfig中使用@EnableA注解,即可获得导入的配置类AConfig中的Bean a。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_01.jpg?sign=1739625685-8Yows3MgTi1o1MlxWuDc76HqPeWTQdIe-0-2f739a3cf93d1111b0b154ed342a2330)
在JavaConfig中使用CommandLineRunner查看Bean的内容,执行结果如图3-8所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_02.jpg?sign=1739625685-jzceX08AwenQS9M3QcRJw0Jm1bIVxsqr-0-32db148b05ae0f3c0829a7853b90fb25)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_03.jpg?sign=1739625685-9rAlHDx3P9CJPuTiGxPr4IvoXLHnUzfQ-0-07bf05f9f58ebf157c88faf96d4811e8)
图3-8
2.配置类选择器ImportSelector的实现
在这个例子中,通过注解选择生效的配置类,注解定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_04.jpg?sign=1739625685-xeS27cmqbTPX14OsCKIRkGAIxjv5iPzx-0-e893361c3c79ade9cec7101ae570234f)
在io.github.wiselyman.selector中定义选择器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_63_05.jpg?sign=1739625685-hwoqiWG5xfpuOdbLyMScmIdqCwCn28S8-0-225a5e7494fc14dabf40182c3f4303c1)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_01.jpg?sign=1739625685-8aW24yoVkDIHcMPMXkgxAHXNIFJUn7uw-0-5af132fe3630a84fac7a08d9eeff1f6f)
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=1739625685-MOWZLdjGn7TupEDqd0Kl311aEdqXL8Gq-0-81d552af55b3058f383c70fb93b691d0)
BLowercaseConfig的定义如下。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_03.jpg?sign=1739625685-z0uXn2scHWkfSsc84BQUtkg5R4uJHrkg-0-5d2f9d11eddbb2da5df6ca3cd2dbcac6)
在JavaConfig中使用@EnableB,并用CommandLineRunner检验。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_04.jpg?sign=1739625685-UbtNw97DKI7GxdfrO5zKc3wiZQrpO5ym-0-ec298c193e94c8451b50d0ce27febd08)
运行结果如图3-9所示。
若将isUppercase设置为false,则执行结果如图3-10所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_64_05.jpg?sign=1739625685-fS1JMzJlEvRM3ufKdOggWOD4bnYX1LOs-0-cde6a0594fe94ced1be18b298d14f77a)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_01.jpg?sign=1739625685-eGZbdwDLWBGSEBdXHLNkv5fHiTEgFxfy-0-7846c7b01525746f344fd693113b498c)
图3-9
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_02.jpg?sign=1739625685-cXDUCnjmsln0SX9ssAwNP6M6i1eeF7JL-0-95830165263515d57ce26877417ca71c)
图3-10
3.动态注册器ImportBeanDefinitionRegistrar的实现
本例通过ImportBeanDefinitionRegistrar动态注册Bean到容器里。
注解定义如下:
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_03.jpg?sign=1739625685-96f9uonYfmMHubTND9MI0R3mqltHnYEM-0-f0a2761940569cb49b40d8b34ae13ee9)
在io.github.wiselyman.registrar中定义注册器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_65_04.jpg?sign=1739625685-17P7oMlZUiydrMfRk2GpZTCudgGSWxjV-0-eec67e5882649bf36d06e74fe134bb62)
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=1739625685-zajckxVZ8u0khNxd4T6pTSXXQzvowwet-0-8215a0821a392d900b21fe5bec9f2912)
IntelliJ IDEA可以检测到静态注册的Bean,但检测不到动态注册的Bean,因而IDE会标识红色,如图3-11中方框所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_02.jpg?sign=1739625685-QovCBcleBuil8XxgRaBcvUjoDFOVVJ7p-0-d5f92ba468314053ade5706e6837f34c)
图3-11
但可以正常运行,运行结果如图3-12所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_03.jpg?sign=1739625685-VMI0CyqpuaXcqH8SgEyQr3xDimDJxs9W-0-a01d7511adf2fced8c0ecd4dd975aa41)
图3-12
4.混合使用
@Import支持导入配置类的数组,因而我们可以混合上面三种配置,定义一个注解,使其具备上面三个功能。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_66_04.jpg?sign=1739625685-GuLT9pZKwgTmMtAyMyvUKj9wOsnB3XD2-0-33b5d036ef84f9b63eb97645522c7a06)
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_01.jpg?sign=1739625685-CwjLa30GW1rIKnuwHwM2oiBqGhwqMlJy-0-6eacce3026674a20dcd7ff49b6c50a55)
因为选择器里指定了要使用的注解的类,所以需要新建一个选择器。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_02.jpg?sign=1739625685-els869U54mtEqBay7ieHFNdEOOlM2PYV-0-03fc3aeeacaadc2a636a3e0b1e0d71b9)
在JavaConfig中启用@EnableABC,并用CommandLineRunner进行检验。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_03.jpg?sign=1739625685-AiTjrhw9aUHYKRNjd3qOh1PDXRrx2PR0-0-d7930b91ebf9e0c20df99a932e663ed8)
校验结果如图3-13所示。
![](https://epubservercos.yuewen.com/E5E2EB/18096059808236406/epubprivate/OEBPS/Images/37792_67_04.jpg?sign=1739625685-eEY7JVUwPokvP2HWq7eCIKhnaGjq5JCi-0-d3d7a845cc91624f374e3a125af218bd)
图3-13