一. 先完成自定义starter
(一)新建maven jar工程
工程名为zdy-spring-boot-starter,导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
(二)编写javaBean
package com.lagou.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "simplebean")
public class SimpleBean {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "SimpleBean{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
(三)编写配置类MyAutoConfiguration
package com.lagou.config;
import com.lagou.pojo.SimpleBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnBean(ConfigMarker.class)//该注解的意思是在上下文中必须存在ConfigMarker.class这个bean,才会让当前自动配置类生效
public class MyAutoConfiguration {
static {
System.out.println("MyAutoConfiguration init.... ");
}
@Bean
public SimpleBean simpleBean(){
return new SimpleBean();
}
}
(四)resources下创建/META-INF/spring.factories
注意:
META-INF
是自己手动创建的目录,
spring.factories
也是手动创建的文件
,
在该文件中配置自
己的自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.lagou.config.MyAutoConfiguration
上面这句话的意思就是
SpringBoot
启动的时候会去加载我们的
simpleBean
到
IOC
容器中。这其实
是一种变形的
SPI
机制
二. 使用自定义starter
(一)创建工程spring-boot-mytest,导入依赖
<?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.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lagou</groupId>
<artifactId>spring-boot-mytest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-mytest</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.lagou</groupId>
<artifactId>zdy-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(二)在全局配置文件中配置属性值
server.port=8080
simplebean.id=1
simplebean.name=子慕
(三)编写测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootMytestApplicationTests {
@Autowired
private SimpleBean simpleBean;
@Test
public void contextLoads() {
System.out.println(simpleBean);
}
}
三. 热插拔技术
还记得我们经常会在启动类
Application
上面加
@EnableXXX
注解吗?
其实这个
@Enablexxx
注解就是一种热拔插技术,加了这个注解就可以启动对应的
starter
,当不需
要对应的
starter
的时候只需要把这个注解注释掉就行,是不是很优雅呢?那么这是如何实现的
呢?
(一)改造zdy工程新增热插拔支持类
1. 新增标记类ConfigMarker
package com.lagou.config;
public class ConfigMarker {
}
2. 新增EnableRegisterServer注解
package com.lagou.config;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ConfigMarker.class)//该注解将某个组件类生成实例,添加到容器中
public @interface EnableRegisterServer {
}
3. 改造 MyAutoConfiguration
新增条件注解
@ConditionalOnBean(ConfigMarker.class)
,
@ConditionalOnBean
这个是条件注解,前面的意思代表只有当期上下文中含有
ConfigMarker
对象,被标注的类才会被实例化。
@ConditionalOnBean(ConfigMarker.class)//该注解的意思是在上下文中必须存在ConfigMarker.class这个bean,才会让当前自动配置类生效
public class MyAutoConfiguration {}
(二)改造service工程
在启动类上新增@EnableImRegisterServer注解
package com.lagou;
import com.lagou.config.EnableRegisterServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication//标注在类上说明这个类是`SpringBoot`的主配置类
@EnableRegisterServer
public class SpringBootMytestApplication{
public static void main(String[] args) {
SpringApplication.run(SpringBootMytestApplication.class, args);
}
/* @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 这里要指向核心启动类
return builder.sources(SpringBootMytestApplication.class);
}*/
}
到此热插拔就实现好了,当你加了
@EnableImRegisterServer
的时候启动
zdy
工程就会自动装配
SimpleBean
,反之则不装配。
让的原理也很简单,当加了
@EnableImRegisterServer
注解的时候,由于这个注解使用了
@Import({ConfigMarker.class})
,所以会导致
Spring
去加载
ConfigMarker
到上下文中,而
又因为条件注解
@ConditionalOnBean(ConfigMarker.class)
的存在,所以
MyAutoConfiguration
类就会被实例化。
四. 关于条件注解
- @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
- @ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean。
- @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。基于SpEL表达式的条件判断。
- @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个 Bean。
- @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。
- @ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。
- @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
- @ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
- @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
- @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
- @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
- @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。