本章将介绍 @ConditionalOnJava 注解的用法,该注解将根据应用程序正在运行的 JVM 版本进行匹配 @Conditional 注解。
在开始使用 @ConditionalOnJava 注解之前,我们先看看它的源码,如下:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnJavaCondition.class)
public @interface ConditionalOnJava {
   /**
    * 指定在 value() 中配置的值应该怎样去匹配边界。
    * 默认为 Range.EQUAL_OR_NEWER,即大于等于
    */
   Range range() default Range.EQUAL_OR_NEWER;
   /**
    * JavaVersion 进行检查。使用 range() 来指定配置的值是上限还是下限
    */
   JavaVersion value();
   /**
    * Range 可选项
    */
   enum Range {
      // 等于或大于指定的 JavaVersion
      EQUAL_OR_NEWER,
      // 小于指定的 JavaVersion
      OLDER_THAN
   }
}继续分析一下 OnJavaCondition 类的 getMatchOutcome() 方法的源码,如下:
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // 获取 @ConditionalOnJava 注解的属性和属性值
    Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnJava.class.getName());
    // 获取 range 属性的值
    Range range = (Range) attributes.get("range");
    // 获取 value 属性的值
    JavaVersion version = (JavaVersion) attributes.get("value");
    // 与当前运行的 JVM 版本进行比较
    return getMatchOutcome(range, JVM_VERSION, version);
}
protected ConditionOutcome getMatchOutcome(Range range, JavaVersion runningVersion, JavaVersion version) {
    // 版本比较
    boolean match = isWithin(runningVersion, range, version);
    // 构建提示信息
    String expected = String.format((range != Range.EQUAL_OR_NEWER) ? "(older than %s)" : "(%s or newer)", version);
    ConditionMessage message = ConditionMessage.forCondition(ConditionalOnJava.class, expected)
            .foundExactly(runningVersion);
    return new ConditionOutcome(match, message);
}
private boolean isWithin(JavaVersion runningVersion, Range range, JavaVersion version) {
    // 判断运行的JVM版本是否大于等于指定版本
    if (range == Range.EQUAL_OR_NEWER) {
        return runningVersion.isEqualOrNewerThan(version);
    }
    // 判断运行的JVM版本是否小于指定版本
    if (range == Range.OLDER_THAN) {
        return runningVersion.isOlderThan(version);
    }
    throw new IllegalStateException("Unknown range " + range);
}(1)创建两个服务,分别为 UserService(用户服务) 和 OrderService(订单服务),如下:
a、UserService.java
package com.huangx.springboot.autoconfig.service;
public class UserService {
    // 什么也不做
}b、OrderService.java
package com.huangx.springboot.autoconfig.service;
public class OrderService {
    // 什么也不做
}(2)创建用户和订单 @Configuration 配置类,如下:
a、UserConfig.java
package com.huangx.springboot.autoconfig.config;
import com.huangx.springboot.autoconfig.service.UserService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;
import org.springframework.boot.system.JavaVersion;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
// 要求 JDK 必须大于等于 1.8
// 注意:默认 range 为 Range.EQUAL_OR_NEWER,即大于等于
@ConditionalOnJava(JavaVersion.EIGHT)
public class UserConfig {
    @Bean
    public UserService userService() {
        System.out.println("UserService -> userService()");
        return new UserService();
    }
}b、OrderConfig.java
package com.huangx.springboot.autoconfig.config;
import com.huangx.springboot.autoconfig.service.OrderService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;
import org.springframework.boot.system.JavaVersion;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
// 要求 JDK 必须大于等于 JDK9
// 注意:默认 range 为 Range.EQUAL_OR_NEWER,即大于等于
@ConditionalOnJava(value = JavaVersion.NINE,
        range = ConditionalOnJava.Range.EQUAL_OR_NEWER)
public class OrderConfig {
    @Bean
    public OrderService orderService() {
        System.out.println("OrderConfig -> orderService()");
        return new OrderService();
    }
}(3)客户端代码,验证用户和订单服务是否被实例化。如下:
package com.huangx.springboot.autoconfig;
import com.huangx.springboot.autoconfig.service.OrderService;
import com.huangx.springboot.autoconfig.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class Demo5Application {
    @Autowired
    private ApplicationContext applicationContext;
    public static void main(String[] args) {
        SpringApplication.run(Demo5Application.class, args);
    }
    @GetMapping("/")
    public String index() {
        UserService userService = null;
        try {
            userService = applicationContext.getBean(UserService.class);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        OrderService orderService = null;
        try {
            orderService = applicationContext.getBean(OrderService.class);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        return "userService=" + userService + "<br/>" +
                "orderService=" + orderService;
    }
}启动 Spring Boot 程序,然后在浏览器中访问 http://localhost:8080 地址,运行效果如下图:

