[讀書筆記] 二、條件注解@Conditional,組合注解,元注解


一、條件注解@Conditional,組合注解,元注解

1.

@Conditional:滿足特定條件創建一個Bean,SpringBoot就是利用這個特性進行自動配置的。

例子:

首先,兩個Condition,判斷當前系統是否是Windows或者Linux(True False)

然后,2個ListService實現類,表明不同系統下的ListService實現。

主要,ConditionConfig使用了Java配置與@Conditional注解,根據LinuxCondition,或者WindowsCondition作為判斷條件

產生相應與系統匹配的實現類。

最后,App.java 測試成功。

package com.springboot.springboot_test2_1;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
        return arg0.getEnvironment().getProperty("os.name").contains("Linux");
    }

}
LinuxCondition.java
package com.springboot.springboot_test2_1;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
        return arg0.getEnvironment().getProperty("os.name").contains("Windows");
    }

}
WindowsCondition.java
package com.springboot.springboot_test2_1;

public interface ListService {
    public String showListCmd();
}
ListService.java
package com.springboot.springboot_test2_1;

public class LinuxListService implements ListService{

    @Override
    public String showListCmd() {
        return "ls";
    }
    
}
LinuxListService.java
package com.springboot.springboot_test2_1;

public class WindowsListService implements ListService{

    @Override
    public String showListCmd() {
        return "dir";
    }
    
}
WindowsListService.java
package com.springboot.springboot_test2_1;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConditionConfig {

    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windowsListService() {
        return new WindowsListService();
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() {
        return new LinuxListService();
    }

}
ConditionConfig.java
package com.springboot.springboot_test2_1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Hello world!
 * 
 */
public class App {
    public static void main(String[] args) {
        
        ApplicationContext context = new AnnotationConfigApplicationContext(
                ConditionConfig.class);
        
        ListService ls = context.getBean(ListService.class);
        System.out.println(context.getEnvironment().getProperty("os.name")
                + "系統下的列表命令為:" + ls.showListCmd());
    }
}
App.java

2.

元注解:可以注解到別的注解上的注解。

組合注解:元注解+被注解=組合注解。

例子:

package com.springboot.springboot_test2_1;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan
public @interface testConfig {
    String[] value() default{};
}
testConfig.java

二、通過條件注解@Conditional,組合注解,元注解理解SpringBoot的自動配置

@SpringBootApplication,源碼:

@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters={@org.springframework.context.annotation.ComponentScan.Filter(type=org.springframework.context.annotation.FilterType.CUSTOM, classes={org.springframework.boot.context.TypeExcludeFilter.class}), @org.springframework.context.annotation.ComponentScan.Filter(type=org.springframework.context.annotation.FilterType.CUSTOM, classes={AutoConfigurationExcludeFilter.class})})
public @interface SpringBootApplication
{
  @AliasFor(annotation=EnableAutoConfiguration.class, attribute="exclude")
  Class<?>[] exclude() default {};
  
  @AliasFor(annotation=EnableAutoConfiguration.class, attribute="excludeName")
  String[] excludeName() default {};
  
  @AliasFor(annotation=ComponentScan.class, attribute="basePackages")
  String[] scanBasePackages() default {};
  
  @AliasFor(annotation=ComponentScan.class, attribute="basePackageClasses")
  Class<?>[] scanBasePackageClasses() default {};
}
SpringBootApplication源碼

它的核心功能是由@EnableAutoConfiguration注解提供的,

@EnableAutoConfiguration,源碼:

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};

}
EnableAutoConfiguration源碼

@EnableAutoConfiguration其中的@AutoConfigurationPackage,會掃描/META-INF/spring.factories文件中的jar包,

spring.factories文件如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

……

2、核心注解

spring.factories文件里每一個xxxAutoConfiguration文件一般都會有下面的條件注解:

@ConditionalOnBean:當容器里有指定Bean的條件下

@ConditionalOnClass:當類路徑下有指定類的條件下

@ConditionalOnExpression:基於SpEL表達式作為判斷條件

@ConditionalOnJava:基於JV版本作為判斷條件

@ConditionalOnJndi:在JNDI存在的條件下差在指定的位置

@ConditionalOnMissingBean:當容器里沒有指定Bean的情況下

@ConditionalOnMissingClass:當類路徑下沒有指定類的條件下

@ConditionalOnNotWebApplication:當前項目不是Web項目的條件下

@ConditionalOnProperty:指定的屬性是否有指定的值

@ConditionalOnResource:類路徑是否有指定的值

@ConditionalOnSingleCandidate:當指定Bean在容器中只有一個,或者雖然有多個但是指定首選Bean

@ConditionalOnWebApplication:當前項目是Web項目的條件下。

上面@ConditionalOnXXX都是組合@Conditional元注解,使用了不同的條件Condition

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM