Loading... <p><img src="https://cdn.ashitakaze.cn/blog/600a3d75ecfe49029329f6529ba485ad.png" alt="在这里插入图片描述" title="在这里插入图片描述"style=""></p><h3>文章目录</h3><ul><li><ul><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#_4" target="_blank"><i data-feather="external-link"></i>一、问题的描述</a></span></li><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#_60" target="_blank"><i data-feather="external-link"></i>二、相对低级解决方案</a></span></li><li><ul><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#21_Primary_64" target="_blank"><i data-feather="external-link"></i>2.1. 方案一:使用<code>@Primary</code>注解</a></span></li><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#22__Resource_74" target="_blank"><i data-feather="external-link"></i>2.2. 方案二:使用<code>@Resource</code>注解</a></span></li><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#23Qualifier_91" target="_blank"><i data-feather="external-link"></i>2.3.方案三:使用<code>@Qualifier</code>注解</a></span></li></ul></li><li><span class="external-link"><a class="no-external-link" href="https://blog.csdn.net/hanxiaotongtong/article/details/123252830?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-5.nonecase#_105" target="_blank"><i data-feather="external-link"></i>三、相对高级的解决方案</a></span></li></ul></li></ul><h2>一、问题的描述</h2><p>在实际的系统应用开发中我经常会遇到这样的一类需求,相信大家在工作中也会经常遇到:</p><ul><li>同一个系统在多个省份部署。</li><li>一个业务在北京是一种实现方式,是基于北京用户的需求。</li><li>同样的业务在上海是另外一种实现方式,与北京的实现方式大同小异</li></ul><p>遇到这样的需求,我们通常会定义一个业务实现的接口,比如:</p><pre><code>public interface IDemoService { public void doSomething(); } </code></pre><p>在北京环境下这样实现,比如:</p><pre><code>@Component public class DemoServiceBeijing implements IDemoService { @Override public void doSomething() {System.out.println("北京的业务实现");} }</code></pre><p>在上海环境下这样实现,比如:</p><pre><code>@Component public class DemoServiceShanghai implements IDemoService { @Override public void doSomething() {System.out.println("上海的业务实现");} }</code></pre><p>然后我们写一个模拟业务测试用例</p><pre><code>@SpringBootTest class DemoApplicationTests { //这里注入的demoService是DemoServiceShanghai,还是DemoServiceBeijing? @Resource IDemoService demoService; @Test void testDemoService() { demoService.doSomething(); } } </code></pre><p>当我们执行这个测试用例的时候一定会报错,因为Spring发现了两个IDemoService的实现类。它不知道去实例化哪一个实现类,来作为IDemoService的实际业务处理bean。当然我们期望的状态是:</p><ul><li>在北京部署系统的时候,使用DemoServiceBeijing作为IDemoService的实现类完成依赖注入</li><li>在上海部署系统的时候,使用DemoServiceShanghai作为IDemoService的实现类完成依赖注入</li></ul><h2>二、相对低级解决方案</h2><p>面对上面的需求,先说几个相对低级的解决方案,这几个方案虽然可以实现我们期望的状态,但是对运维不够友好。</p><h3>2.1. 方案一:使用<code>@Primary</code>注解</h3><p>假如在北京部署系统的时候,在DemoServiceBeijing的类上面加上<code>@Primary</code>,该注解的作用就是强迫从多个实现类里面选一个实现类,如果Spring不知道选哪一个,我们告诉它一个默认的。</p><pre><code>@Primary @Component public class DemoServiceBeijing implements IDemoService { </code></pre><h3>2.2. 方案二:使用<code>@Resource</code>注解</h3><p>因为Resource注解默认使用名称进行<span class="external-link"><a class="no-external-link" href="https://so.csdn.net/so/search?q=%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5&spm=1001.2101.3001.7020" target="_blank"><i data-feather="external-link"></i>依赖注入</a></span>,所以变量名明确叫做demoServiceBeijing(首字母小写),使用的就是DemoServiceBeijing实现类。</p><pre><code>@Resource IDemoService demoServiceBeijing; //这里的变量名称指定了bean名称 //IDemoService demoService; 被替换掉 </code></pre><p>或者</p><pre><code>@Resource(name = "demoServiceBeijing") //使用resource注解明确指定名称 IDemoService demoService; </code></pre><h3>2.3.方案三:使用<code>@Qualifier</code>注解</h3><p>与上文同样的道理,使用<code>@Qualifier</code>注解,指定bean的名称进行依赖注入</p><pre><code>@Qualifier("demoServiceBeijing") //使用Qualifier注解明确指定名称 @Resource IDemoService demoService; </code></pre><p>上面所提到的三个方案虽然都可以解决:在不同的部署环境下使用不同的接口实现类完成依赖注入的问题。但是这样不好,因为一旦我们要把部署环境从beijing(北京)换成shanghai(上海),就需要把上面的注解的位置或者内容全都修改一遍(所有的实现类代码都要修改)。</p><h2>三、相对高级的解决方案</h2><p>我们提出进一步的期望:就是只修改一个配置就能完成部署环境切换的操作。比如:</p><pre><code>deploy: province: beijing </code></pre><p>当我们期望把部署环境从北京切换到上海的时候,只需要将上文配置中的beijing 改成 shanghai ,这该怎么实现呢?</p><ul><li>在北京的实现类上面加上ConditionalOnProperty注解,havingValue的值为beijing</li></ul><pre><code>@Component @ConditionalOnProperty(value="deploy.province",havingValue = "beijing") public class DemoServiceBeijing implements IDemoService { </code></pre><ul><li>在上海的实现类上面加上ConditionalOnProperty注解,havingValue的值为shanghai</li></ul><pre><code>@Component @ConditionalOnProperty(value="deploy.province",havingValue = "shanghai") public class DemoServiceShanghai implements IDemoService { </code></pre><p><strong>ConditionalOnProperty注解在这里的作用就是</strong> :读取配置文件发现<code>deploy.province</code>,并将该配置的值与havingValue匹配,匹配上哪一个就实例化哪一个类作为该接口的实现类bean注入到Spring容器中(当然注入过程需要配合<code>@Component</code>注解实现)。</p> 最后修改:2023 年 08 月 04 日 © 转载自他站 打赏 赞赏作者 支付宝微信 赞 1 如果觉得我的文章对你有用,请随意赞赏