[读书笔记] 二、条件注解@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

 

posted on 2017-05-08 15:25  懂技术爱生活  阅读(11458)  评论(0编辑  收藏  举报

导航