解锁Spring Boot新技巧,搞懂这些神奇注解,让你的项目更有料!

作者:微信小助手

发布时间:2024-01-24T22:47:17


                成长不是瞬间的华丽转身

     而是每天坚持努力的积累


STRAT

乘风破浪 | 直挂云帆

本篇来聊聊Springboot中的条件注解,这些条件注解使得开发者能够根据运行时环境的不同,动态的选择性地加载或配置一些 Bean 或组件。通过合理使用条件注解,可以实现更灵活和可配置的应用程序




  条件注解介绍以及解析

  1. ConditionalOnBean :是否存在某个某类或某个名字的Bean。
  2. ConditionalOnMissingBean :是否缺失某个某类或某个名字的Bean。
  3. ConditionalOnSingleCandidate :是否符合指定类型的Bean只有一个。
  4. ConditionalOnClass :是否存在某个类。
  5. ConditionalOnMissingClass :是否缺失某个类。
  6. ConditionalOnExpression :指定的表达式返回的是true还是false。
  7. ConditionalOnJava :判断Java版本。
  8. ConditionalOnJndi :JNDI指定的资源是否存在。
  9. ConditionalOnWebApplication :当前应用是一个Web应用。
  10. ConditionalOnNotWebApplication :当前应用不是一个Web应用。
  11. ConditionalOnProperty :Environment中是否存在某个属性。
  12. ConditionalOnResource :指定的资源是否存在。
  13. ConditionalOnWarDeployment :项目是否以War包部署的方式运行。
  14. ConditionalOnCloudPlatform 是否在某个云平台上。
当Spring在解析某一个条件注解的时候,首先会来匹配 SpringBootCondition中的matches方法 ,该方法里面会根据不同的逻辑去处理。
            </ul>
            <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__meta">@Override</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">final</span> <span class="code-snippet__keyword">boolean</span> <span class="code-snippet__title">matches</span><span class="code-snippet__params">(ConditionContext context, AnnotatedTypeMetadata metadata)</span> </span>{</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 针对每个条件注解进行条件判断</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 条件注解写在了哪个类上,或哪个方法上</span></span></code><code><span class="code-snippet_outer">    String classOrMethodName = getClassOrMethodName(metadata);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 条件的判断结果</span></span></code><code><span class="code-snippet_outer">        ConditionOutcome outcome = getMatchOutcome(context, metadata);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 如果log的日志级别为trace,那就直接记录当前条件的判断结果</span></span></code><code><span class="code-snippet_outer">        logOutcome(classOrMethodName, outcome);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 将判断结果记录到ConditionEvaluationReport中</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">//ConditionEvaluationReportLoggingListener会在收到ContextRefreshedEvent事件后把判断结果用日志的方式打印出来</span></span></code><code><span class="code-snippet_outer">        recordEvaluation(context, classOrMethodName, outcome);</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">return</span> outcome.isMatch();</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">catch</span> (NoClassDefFoundError ex) {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">throw</span> <span class="code-snippet__keyword">new</span> IllegalStateException(<span class="code-snippet__string">"Could not evaluate condition on "</span> + classOrMethodName + <span class="code-snippet__string">" due to "</span></span></code><code><span class="code-snippet_outer">                + ex.getMessage() + <span class="code-snippet__string">" not found. Make sure your own configuration does not rely on "</span></span></code><code><span class="code-snippet_outer">                + <span class="code-snippet__string">"that class. This can also happen if you are "</span></span></code><code><span class="code-snippet_outer">                + <span class="code-snippet__string">"@ComponentScanning a springframework package (e.g. if you "</span></span></code><code><span class="code-snippet_outer">                + <span class="code-snippet__string">"put a @ComponentScan in the default package by mistake)"</span>, ex);</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">catch</span> (RuntimeException ex) {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">throw</span> <span class="code-snippet__keyword">new</span> IllegalStateException(<span class="code-snippet__string">"Error processing condition on "</span> + getName(metadata), ex);</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">}</span></code></pre>
           </section>
          </section>
         </section>
        </section>
       </section>
      </section>
     </section>
    </section>
    


  各条件注解的原理 

@ConditionOnClass
判断某个类是否存在 ,执行OnClassCondition.getMatchOutcome方法。
      </ul>
      <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {</span></code><code><span class="code-snippet_outer">    ClassLoader classLoader = context.getClassLoader();</span></code><code><span class="code-snippet_outer">    ConditionMessage matchMessage = ConditionMessage.empty();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 拿到ConditionalOnClass注解中的value值,也就是要判断是否存在的类名</span></span></code><code><span class="code-snippet_outer">    List&lt;String&gt; onClasses = getCandidates(metadata, ConditionalOnClass.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (onClasses != <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 判断onClasses中不存在的类</span></span></code><code><span class="code-snippet_outer">        List&lt;String&gt; missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 如果有缺失的类,那就表示不匹配</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (!missing.isEmpty()) {</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.<span class="code-snippet__keyword">class</span>)</span></code><code><span class="code-snippet_outer">                    .didNotFind(<span class="code-snippet__string">"required class"</span>, <span class="code-snippet__string">"required classes"</span>).items(Style.QUOTE, missing));</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 否则就表示匹配</span></span></code><code><span class="code-snippet_outer">        matchMessage = matchMessage.andCondition(ConditionalOnClass.<span class="code-snippet__keyword">class</span>)</span></code><code><span class="code-snippet_outer">                .found(<span class="code-snippet__string">"required class"</span>, <span class="code-snippet__string">"required classes"</span>)</span></code><code><span class="code-snippet_outer">                .items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 和上面类似,只不过是判断onMissingClasses是不是全部缺失,如果是则表示匹配</span></span></code><code><span class="code-snippet_outer">    List&lt;String&gt; onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (onMissingClasses != <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">        List&lt;String&gt; present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (!present.isEmpty()) {</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.<span class="code-snippet__keyword">class</span>)</span></code><code><span class="code-snippet_outer">                    .found(<span class="code-snippet__string">"unwanted class"</span>, <span class="code-snippet__string">"unwanted classes"</span>).items(Style.QUOTE, present));</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">        matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.<span class="code-snippet__keyword">class</span>)</span></code><code><span class="code-snippet_outer">                .didNotFind(<span class="code-snippet__string">"unwanted class"</span>, <span class="code-snippet__string">"unwanted classes"</span>)</span></code><code><span class="code-snippet_outer">                .items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">return</span> ConditionOutcome.match(matchMessage);</span></code><code><span class="code-snippet_outer">}</span></code></pre>
     </section>
     <section data-tools="135编辑器" data-id="7">
      <section style="padding-left: 10px;border-left: 5px solid rgb(170, 170, 170);margin: 10px auto;">
       <section style="font-size: 13px;letter-spacing: 1px;line-height: 1.75em;color: rgba(102, 102, 102, 0.8);">
        <section data-role="list">
         <ul class="list-paddingleft-1" style="padding-left: 30px;list-style-position: outside;margin-left: 8px;margin-right: 8px;">
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="font-size: 15px;caret-color: red;color: rgb(96, 96, 96);letter-spacing: 1px;">获取ConditionalOnClass注解中的value值。</span>
            <ne-clipboard source="https%3A%2F%2Fwww.yuque.com%2Fdream_lsj%2Fyddpep%2Fpunmt1zhmirb2y8x%23Bvjvx"></ne-clipboard>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">判断是否存在不配的类,判断逻辑为</span>
            <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);"> Class.<em>forName</em>(className);</span>
            <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;"> 存在就会直接返回。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">不存在就会获取ConditionalOnMissingClass注解中的value值,然后处理逻辑与前面一直。</span>
           </section></li>
         </ul>
        </section>
        <section typography="classic" style="height: 0px;overflow: hidden;">
         <br>
        </section>
       </section>
      </section>
     </section>
     <section typography="classic">
      <section style="min-height: 24px;margin: 24px 8px;line-height: 1.75em;">
       <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">Spring中会去每个注解的解析,但是springBoot中会</span>
       <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">提前将@ConditionalOnClass与@ConditionalOnClass</span>
       <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">一起解析,如果发现不匹配能够快速的处理,但是如果都成立,那么这个回去重复执行。</span>
      </section>
     </section>
    </section>
    
@ConditionOnBean

@ConditionalOnBean和@ConditionalOnClass的底层实现应该是差不多的,一个是判断Bean存不存在,一个是判断类存不存在,事实上也确实差不多。  

@ConditionalOnBean和@ConditionalOnMissingBean对应的都是OnBeanCondition类, OnBeanCondition类也是继承了SpringBootCondition,所以SpringBootCondition类中的getMatchOutcome方法才是匹配逻辑。

      </ul>
      <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__meta">@Override</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {</span></code><code><span class="code-snippet_outer">    ConditionMessage matchMessage = ConditionMessage.empty();</span></code><code><span class="code-snippet_outer">    MergedAnnotations annotations = metadata.getAnnotations();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 如果存在ConditionalOnBean注解</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (annotations.isPresent(ConditionalOnBean.<span class="code-snippet__keyword">class</span>)) {</span></code><code><span class="code-snippet_outer">        Spec&lt;ConditionalOnBean&gt; spec = new Spec&lt;&gt;(context, metadata, annotations, ConditionalOnBean.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer">        MatchResult matchResult = getMatchingBeans(context, spec);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 如果某个Bean不存在</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (!matchResult.isAllMatched()) {</span></code><code><span class="code-snippet_outer">            String reason = createOnBeanNoMatchReason(matchResult);</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(spec.message().because(reason));</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 所有Bean都存在</span></span></code><code><span class="code-snippet_outer">        matchMessage = spec.message(matchMessage).found(<span class="code-snippet__string">"bean"</span>, <span class="code-snippet__string">"beans"</span>).items(Style.QUOTE, matchResult.getNamesOfAllMatches());</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 如果存在ConditionalOnSingleCandidate注解</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (metadata.isAnnotated(ConditionalOnSingleCandidate.<span class="code-snippet__keyword">class</span>.getName())) {</span></code><code><span class="code-snippet_outer">        Spec&lt;ConditionalOnSingleCandidate&gt; spec = new SingleCandidateSpec(context, metadata, annotations);</span></code><code><span class="code-snippet_outer">        MatchResult matchResult = getMatchingBeans(context, spec);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// Bean不存在</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (!matchResult.isAllMatched()) {</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(spec.message().didNotFind(<span class="code-snippet__string">"any beans"</span>).atAll());</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// Bean存在</span></span></code><code><span class="code-snippet_outer">        Set&lt;String&gt; allBeans = matchResult.getNamesOfAllMatches();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 如果只有一个</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (allBeans.size() == <span class="code-snippet__number">1</span>) {</span></code><code><span class="code-snippet_outer">            matchMessage = spec.message(matchMessage).found(<span class="code-snippet__string">"a single bean"</span>).items(Style.QUOTE, allBeans);</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// 如果有多个</span></span></code><code><span class="code-snippet_outer">            List&lt;String&gt; primaryBeans = getPrimaryBeans(context.getBeanFactory(), allBeans, spec.getStrategy() == SearchStrategy.ALL);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// 没有主Bean,那就不匹配</span></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (primaryBeans.isEmpty()) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(</span></code><code><span class="code-snippet_outer">                    spec.message().didNotFind(<span class="code-snippet__string">"a primary bean from beans"</span>).items(Style.QUOTE, allBeans));</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// 有多个主Bean,那就不匹配</span></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (primaryBeans.size() &gt; <span class="code-snippet__number">1</span>) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">return</span> ConditionOutcome</span></code><code><span class="code-snippet_outer">                    .noMatch(spec.message().found(<span class="code-snippet__string">"multiple primary beans"</span>).items(Style.QUOTE, primaryBeans));</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// 只有一个主Bean</span></span></code><code><span class="code-snippet_outer">            matchMessage = spec.message(matchMessage)</span></code><code><span class="code-snippet_outer">                .found(<span class="code-snippet__string">"a single primary bean '"</span> + primaryBeans.<span class="code-snippet__keyword">get</span>(<span class="code-snippet__number">0</span>) + <span class="code-snippet__string">"' from beans"</span>)</span></code><code><span class="code-snippet_outer">                .items(Style.QUOTE, allBeans);</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__comment">// 存在ConditionalOnMissingBean注解</span></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (metadata.isAnnotated(ConditionalOnMissingBean.<span class="code-snippet__keyword">class</span>.getName())) {</span></code><code><span class="code-snippet_outer">        Spec&lt;ConditionalOnMissingBean&gt; spec = new Spec&lt;&gt;(context, metadata, annotations,</span></code><code><span class="code-snippet_outer">                                                         ConditionalOnMissingBean.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer">        MatchResult matchResult = getMatchingBeans(context, spec);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">//有任意一个Bean存在,那就条件不匹配</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (matchResult.isAnyMatched()) {</span></code><code><span class="code-snippet_outer">            String reason = createOnMissingBeanNoMatchReason(matchResult);</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span> ConditionOutcome.noMatch(spec.message().because(reason));</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// 都不存在在,则匹配</span></span></code><code><span class="code-snippet_outer">        matchMessage = spec.message(matchMessage).didNotFind(<span class="code-snippet__string">"any beans"</span>).atAll();</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">return</span> ConditionOutcome.match(matchMessage);</span></code><code><span class="code-snippet_outer">}</span></code></pre>
     </section>
     <section data-tools="135编辑器" data-id="7">
      <section style="padding-left: 10px;border-left: 5px solid rgb(170, 170, 170);margin: 10px auto;">
       <section style="font-size: 13px;letter-spacing: 1px;line-height: 1.75em;color: rgba(102, 102, 102, 0.8);">
        <section data-role="list">
         <ul class="list-paddingleft-1" style="padding-left: 30px;list-style-position: outside;margin-left: 8px;margin-right: 8px;">
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">当前在解析的类或方法上</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">,</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">是否有@ConditionalOnBean注解,如果有则生成对应的Spec对象,该对象中包含了 用户指定的,要判断的是否存在的Bean的类型。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">调用</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">getMatchingBeans方法进行条件判断</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">&nbsp;。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">只要判断出来某一个Bean不存在,则return,表示条件不匹配 。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">只要所有Bean都存在,则继续执行下面代码 。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">在解析的类或方法上是否有@ConditionalOnSingleCandidate注解</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">,如果有则生成对应的 SingleCandidateSpec对象,该对象中包含了用户指定的,要判断的是否存在的Bean的类型(只能指定一个类 型),并且该类型的Bean只能有一个。</span>
           </section></li>
          <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
           <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">调用getMatchingBeans方法进行条件判断</span>
            <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(96, 96, 96);">。</span>
           </section></li>
         </ul>
        </section>
       </section>
      </section>
     </section>
    </section>
    
@ConditionOnMissingBean

@ConditionalOnMissingBean的作用是用来判断某个Bean是否缺失,如果不存在某个Bean,那就符合该条件。

      </ul>
      <pre class="code-snippet__js" data-lang="ruby"><code><span class="code-snippet_outer">@Configuration(proxyBeanMethods = <span class="code-snippet__literal">false</span>)</span></code><code><span class="code-snippet_outer">@ConditionalOnClass({ Servlet.<span class="code-snippet__keyword">class</span>, Tomcat.<span class="code-snippet__keyword">class</span>, UpgradeProtocol.<span class="code-snippet__keyword">class</span> })</span></code><code><span class="code-snippet_outer">@ConditionalOnMissingBean(value = ServletWebServerFactory.<span class="code-snippet__keyword">class</span>, search = SearchStrategy.CURRENT)</span></code><code><span class="code-snippet_outer">static <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">EmbeddedTomcat</span> {</span></span></code><code><span class="code-snippet_outer">    @Bean</span></code><code><span class="code-snippet_outer">    TomcatServletWebServerFactory tomcatServletWebServerFactory(</span></code><code><span class="code-snippet_outer">        ObjectProvider&lt;TomcatConnectorCustomizer&gt; connectorCustomizers,</span></code><code><span class="code-snippet_outer">        ObjectProvider&lt;TomcatContextCustomizer&gt; contextCustomizers,</span></code><code><span class="code-snippet_outer">        ObjectProvider&lt;TomcatProtocolHandlerCustomizer&lt;?<span class="code-snippet__meta">&gt;&gt; </span>protocolHandlerCustomizers) {</span></code><code><span class="code-snippet_outer">        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__regexp">//</span> orderedStream()调用时会去Spring容器中找到TomcatConnectorCustomizer类型的Bean,</span></code><code><span class="code-snippet_outer">        默认是没有的,程序员可以自己定义</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        factory.getTomcatConnectorCustomizers()</span></code><code><span class="code-snippet_outer">            .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));</span></code><code><span class="code-snippet_outer">        factory.getTomcatContextCustomizers()</span></code><code><span class="code-snippet_outer">            .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));</span></code><code><span class="code-snippet_outer">        factory.getTomcatProtocolHandlerCustomizers()</span></code><code><span class="code-snippet_outer">            .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">return</span> factory;</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">}</span></code></pre>
     </section>
     <section data-tools="135编辑器" data-id="7">
      <section style="padding-left: 10px;border-left: 5px solid rgb(170, 170, 170);margin: 10px auto;">
       <section style="font-size: 13px;letter-spacing: 1px;line-height: 1.75em;color: rgba(102, 102, 102, 0.8);" data-role="list">
        <ul class="list-paddingleft-1" style="padding-left: 30px;list-style-position: outside;margin-left: 8px;margin-right: 8px;">
         <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
          <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
           <span style="caret-color: red;font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">如果用户自己没有定义</span>
           <span style="caret-color: red;font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">ServletWebServerFactory类型</span>
           <span style="caret-color: red;font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">的Bean,那代码中所定义的Bean就会生效。</span>
          </section></li>
         <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
          <section style="color: rgb(102, 102, 102);font-size: 14px;letter-spacing: 1.5px;caret-color: red;margin-top: 8px;margin-bottom: 8px;line-height: 1.75em;">
           <span style="caret-color: red;font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">如果用户自己定义了ServletWebServerFactory类型的Bean,那代码中定义的Bean就不生效 。</span>
          </section></li>
        </ul>
       </section>
      </section>
     </section>
     <section typography="classic">
      <p style="min-height: 24px;margin: 24px 8px;line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;color: rgb(255, 76, 0);">SpringBoot利用该注解来决定到底用用户自己的Bean还是用SpringBoot自定配置的Bean。</span></p>
      <p style="min-height: 24px;margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">如果先解析自动配置然后再解析程序员定义的,那么就会发现该注解里面的判断是错误的,因为你首先来判断是否成立,是在还没有解析程序员定义的Bean之前,所以就会认为是符合该注解,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">实际上只是没有加载程序员定义的,所以必须先去解析程序员定义的,然后最后执行自动配置的</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">。</span></p>
     </section>
    </section>
    


今天先说到这里明天我们继续,这三个注解是我们自定义扩展SpringBoot相关知识点的重要内容。
文章有帮助的话,    点赞 在看转发吧。
一起讨论,谢谢支持哟



长按二维码关注我
每日分享干货