问题
在学习@ConditionalOnClass注解时,我有个百思不得其解的问题,如以下内容
package com.example.child.config;
import com.example.parent.model.Test;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(value = Test.class)
public class TestConfig {
public TestConfig() {
System.out.println("config实例化");
}
}
现在类路径中没有Test这个类,那肯定编译都通不过,所以@Test(value = {Test.class})那肯定需要有Test类,那么Test类肯定在类路径下,一旦有Test类,TestConfig肯定被实例化,那这么配置有什么意义,你是不是有这个疑问?
其实就是通过maven的一些配置让包能通过编译,实际上不让文件进入包中。
spring中的应用
spring中如何做到这种项目中没有SecurityEvaluationContextExtension类,但是却通过编译的。
我看看一看spring-boot的依赖关系
其实就是通过maven配置optional达到的效果,optional允许我们将某些依赖项声明为可选。了解optional可以看看我的另一篇文章,optional详解
示例
我建了三个项目,分别为parent-maven,maven-child,springTest来实践@ConditionalOnClass怎么做到自动配置。
parent-maven
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>parent-maven</name>
<description>parent-maven</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
</dependencies>
</project>
Test代码
package com.example.parent.model;
public class Test {
public Test() {
System.out.println("Test实例化");
}
}
该项目中新建了一个Test类,pom文件中什么依赖都没引入。
打包
安装到maven仓库
maven-child
pom文件
parent-mavenparent-maven<optional>true</optional><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>maven-child</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>maven-child</name>
<description>maven-child</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>parent-maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<optional>true</optional>这一句特别重要,将parent-maven设置为可选的。
TestConfig代码
package com.example.child.config;
import com.example.parent.model.Test;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(value = Test.class)
public class TestConfig {
public TestConfig() {
System.out.println("config实例化");
}
}
TestConfig是我的配置文件类,我想的是当我类路径下有Test时我就加载这个配置文件,没有时我就不加载,当然这个项目时会被打包为一个jar供别的项目使用。
打包
安装到maven仓库
springTest
现在就是重点,我想动态的去加载TestConfig配置文件,当引入依赖时就去配置,像spring的很多自动配置一样。
springTest是一个springBoot项目。
pom文件
maven-childmaven-child<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springTest</name>
<description>springTest</description>
<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.github.shyiko</groupId>
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.21.0</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>maven-child</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我现在引入了maven-child依赖,该依赖中有TestConfig配置文件,当类路径中有Test类时会自动配置。
启动spring
从图中没有看到打印“config实例化”,所以TestConfig配置类没有被加载。
注意:spring启动时需要需要扫到TestConfig类,这点很重要。
现在我想要自动配置怎么办,这是我们就得显示的加上 parent-maven依赖。
在启动spring
成功加载配置文件,spring很多自动配置就是这样做的,都看到这儿点个赞再走吧。