如果是 linux 环境,用以下命令即可获取 spring boot 的骨架 pom.xml
curl -G https://start.spring.io/pom.xml -d dependencies=web,mysql,mybatis -o pom.xml
也可以使用 Postman 等工具实现
若想获取更多用法,请参考
curl https://start.spring.io
步骤1:创建模块,区别在于打包方式选择 war
接下来勾选 Spring Web 支持
步骤2:编写控制器
@Controller
public class MyController {
@RequestMapping("/hello")
public String abc() {
System.out.println("进入了控制器");
return "hello";
}
}
步骤3:编写 jsp 视图,新建 webapp 目录和一个 hello.jsp 文件,注意文件名与控制器方法返回的视图逻辑名一致
src
|- main
|- java
|- resources
|- webapp
|- hello.jsp
步骤4:配置视图路径,打开 application.properties 文件
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
将来 prefix + 控制器方法返回值 + suffix 即为视图完整路径
如果用 mvn 插件 mvn spring-boot:run
或 main 方法测试
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-jasperartifactId>
<scope>providedscope>
dependency>
也可以使用 Idea 配置 tomcat 来测试,此时用的是外置 tomcat
对于 jar 项目,若要支持 jsp,也可以在加入 jasper 依赖的前提下,把 jsp 文件置入 META-INF/resources
阶段一:SpringApplication 构造
阶段二:执行 run 方法
得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器
封装启动 args
准备 Environment 添加命令行参数(*)
ConfigurationPropertySources 处理(*) // 把资源中名字命名规范环境不一致的统一使用xx-xxx解析环境变量
通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理(*)//解析application.properties
绑定 spring.main 到 SpringApplication 对象(*)
打印 banner(*)
创建容器
准备容器
加载 bean 定义
refresh 容器
执行 runner
发布 application ready 事件6️⃣
这其中有异常,发布 application failed 事件7️⃣
带 * 的有独立的示例
对应 SpringApplication 构造
package com.itheima.a39;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
@Configuration
public class A39_1 {
public static void main(String[] args) throws Exception {
System.out.println("1. 演示获取 Bean Definition 源");
SpringApplication spring = new SpringApplication(A39_1.class);
spring.setSources(Set.of("classpath:b01.xml"));
System.out.println("2. 演示推断应用类型");
Method deduceFromClasspath = WebApplicationType.class.getDeclaredMethod("deduceFromClasspath");
deduceFromClasspath.setAccessible(true);
System.out.println("\t应用类型为:"+deduceFromClasspath.invoke(null));
System.out.println("3. 演示 ApplicationContext 初始化器");
spring.addInitializers(applicationContext -> {
if (applicationContext instanceof GenericApplicationContext gac) {
gac.registerBean("bean3", Bean3.class);
}
});
System.out.println("4. 演示监听器与事件");
spring.addListeners(event -> System.out.println("\t事件为:" + event.getClass()));
System.out.println("5. 演示主类推断");
Method deduceMainApplicationClass = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
deduceMainApplicationClass.setAccessible(true);
System.out.println("\t主类是:"+deduceMainApplicationClass.invoke(spring));
ConfigurableApplicationContext context = spring.run(args);
// 创建 ApplicationContext
// 调用初始化器 对 ApplicationContext 做扩展
// ApplicationContext.refresh
for (String name : context.getBeanDefinitionNames()) {
System.out.println("name: " + name + " 来源:" + context.getBeanFactory().getBeanDefinition(name).getResourceDescription());
}
context.close();
/*
学到了什么
a. SpringApplication 构造方法中所做的操作
1. 可以有多种源用来加载 bean 定义
2. 应用类型推断
3. 容器初始化器
4. 演示启动各阶段事件
5. 演示主类推断
*/
}
static class Bean1 {
}
static class Bean2 {
}
static class Bean3 {
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
@Bean
public TomcatServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
对应第1步,并演示 7 个事件
package com.itheima.a39;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import java.lang.reflect.Constructor;
import java.util.List;
public class A39_2 {
public static void main(String[] args) throws Exception{
// 添加 app 监听器
SpringApplication app = new SpringApplication();
app.addListeners(e -> System.out.println(e.getClass()));
// 获取事件发送器实现类名
List<String> names = SpringFactoriesLoader.loadFactoryNames(SpringApplicationRunListener.class, A39_2.class.getClassLoader());
for (String name : names) {
System.out.println(name);
Class<?> clazz = Class.forName(name);
Constructor<?> constructor = clazz.getConstructor(SpringApplication.class, String[].class);
SpringApplicationRunListener publisher = (SpringApplicationRunListener) constructor.newInstance(app, args);
// 发布事件
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
publisher.starting(bootstrapContext); // spring boot 开始启动
publisher.environmentPrepared(bootstrapContext, new StandardEnvironment()); // 环境信息准备完毕
GenericApplicationContext context = new GenericApplicationContext();
publisher.contextPrepared(context); // 在 spring 容器创建,并调用初始化器之后,发送此事件
publisher.contextLoaded(context); // 所有 bean definition 加载完毕
context.refresh();
publisher.started(context); // spring 容器初始化完成(refresh 方法调用完毕)
publisher.running(context); // spring boot 启动完毕
publisher.failed(context, new Exception("出错了")); // spring boot 启动出错
}
/*
学到了什么
a. 如何读取 spring.factories 中的配置
b. run 方法内获取事件发布器 (得到 SpringApplicationRunListeners) 的过程, 对应步骤中
1.获取事件发布器
发布 application starting 事件1️⃣
发布 application environment 已准备事件2️⃣
发布 application context 已初始化事件3️⃣
发布 application prepared 事件4️⃣
发布 application started 事件5️⃣
发布 application ready 事件6️⃣
这其中有异常,发布 application failed 事件7️⃣
*/
}
}
对应第2、8到12步
package com.itheima.a39;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.Set;
// 运行时请添加运行参数 --server.port=8080 debug
public class A39_3 {
@SuppressWarnings("all")
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication();
app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("执行初始化器增强...");
}
});
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args");
DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器");
GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 9. 准备容器");
for (ApplicationContextInitializer initializer : app.getInitializers()) {
initializer.initialize(context);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义");
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
AnnotatedBeanDefinitionReader reader1 = new AnnotatedBeanDefinitionReader(beanFactory);
XmlBeanDefinitionReader reader2 = new XmlBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
reader1.register(Config.class);
reader2.loadBeanDefinitions(new ClassPathResource("b03.xml"));
scanner.scan("com.itheima.a39.sub");
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器");
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println("name:" + name + " 来源:" + beanFactory.getBeanDefinition(name).getResourceDescription());
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner");
for (CommandLineRunner runner : context.getBeansOfType(CommandLineRunner.class).values()) {
runner.run(args);
}
for (ApplicationRunner runner : context.getBeansOfType(ApplicationRunner.class).values()) {
runner.run(arguments);
}
/*
学到了什么
a. 创建容器、加载 bean 定义、refresh, 对应的步骤
*/
}
private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
GenericApplicationContext context = null;
switch (type) {
case SERVLET -> context = new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE -> context = new AnnotationConfigReactiveWebServerApplicationContext();
case NONE -> context = new AnnotationConfigApplicationContext();
}
return context;
}
static class Bean4 {
}
static class Bean5 {
}
static class Bean6 {
}
@Configuration
static class Config {
@Bean
public Bean5 bean5() {
return new Bean5();
}
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
public CommandLineRunner commandLineRunner() {
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {
System.out.println("commandLineRunner()..." + Arrays.toString(args));
}
};
}
@Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner() {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("applicationRunner()..." + Arrays.toString(args.getSourceArgs()));
System.out.println(args.getOptionNames());
System.out.println(args.getOptionValues("server.port"));
System.out.println(args.getNonOptionArgs());
}
};
}
}
}
step3
public class Step3 {
public static void main(String[] args) throws IOException {
ApplicationEnvironment env = new ApplicationEnvironment(); // 系统环境变量, properties, yaml
env.getPropertySources().addLast(new ResourcePropertySource(new ClassPathResource("step3.properties")));
env.getPropertySources().addFirst(new SimpleCommandLinePropertySource(args));
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
// System.out.println(env.getProperty("JAVA_HOME"));
System.out.println(env.getProperty("server.port"));
}
}
step4
package org.springframework.boot;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;
import java.io.IOException;
public class Step4 {
public static void main(String[] args) throws IOException, NoSuchFieldException {
ApplicationEnvironment env = new ApplicationEnvironment();
env.getPropertySources().addLast(
new ResourcePropertySource("step4", new ClassPathResource("step4.properties"))
);
ConfigurationPropertySources.attach(env);
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
System.out.println(env.getProperty("user.first-name"));
System.out.println(env.getProperty("user.middle-name"));
System.out.println(env.getProperty("user.last-name"));
}
}
step5
package org.springframework.boot;
import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.EnvironmentPostProcessorApplicationListener;
import org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor;
import org.springframework.boot.logging.DeferredLog;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.SpringFactoriesLoader;
import javax.swing.*;
import java.util.List;
/*
可以添加参数 --spring.application.json={\"server\":{\"port\":9090}} 测试 SpringApplicationJsonEnvironmentPostProcessor
*/
public class Step5 {
public static void main(String[] args) {
SpringApplication app = new SpringApplication();
app.addListeners(new EnvironmentPostProcessorApplicationListener());
/*List names = SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, Step5.class.getClassLoader());
for (String name : names) {
System.out.println(name);
}*/
EventPublishingRunListener publisher = new EventPublishingRunListener(app, args);
ApplicationEnvironment env = new ApplicationEnvironment();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
publisher.environmentPrepared(new DefaultBootstrapContext(), env);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
}
private static void test1() {
SpringApplication app = new SpringApplication();
ApplicationEnvironment env = new ApplicationEnvironment();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
ConfigDataEnvironmentPostProcessor postProcessor1 = new ConfigDataEnvironmentPostProcessor(new DeferredLogs(), new DefaultBootstrapContext());
postProcessor1.postProcessEnvironment(env, app);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
RandomValuePropertySourceEnvironmentPostProcessor postProcessor2 = new RandomValuePropertySourceEnvironmentPostProcessor(new DeferredLog());
postProcessor2.postProcessEnvironment(env, app);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
for (PropertySource<?> ps : env.getPropertySources()) {
System.out.println(ps);
}
System.out.println(env.getProperty("server.port"));
System.out.println(env.getProperty("random.int"));
System.out.println(env.getProperty("random.int"));
System.out.println(env.getProperty("random.int"));
System.out.println(env.getProperty("random.uuid"));
System.out.println(env.getProperty("random.uuid"));
System.out.println(env.getProperty("random.uuid"));
}
}
step6
package org.springframework.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;
import java.io.IOException;
public class Step6 {
// 绑定 spring.main 前缀的 key value 至 SpringApplication, 请通过 debug 查看
public static void main(String[] args) throws IOException {
SpringApplication application = new SpringApplication();
ApplicationEnvironment env = new ApplicationEnvironment();
env.getPropertySources().addLast(new ResourcePropertySource("step4", new ClassPathResource("step4.properties")));
env.getPropertySources().addLast(new ResourcePropertySource("step6", new ClassPathResource("step6.properties")));
// User user = Binder.get(env).bind("user", User.class).get();
// System.out.println(user);
// User user = new User();
// Binder.get(env).bind("user", Bindable.ofInstance(user));
// System.out.println(user);
System.out.println(application);
Binder.get(env).bind("spring.main", Bindable.ofInstance(application));
System.out.println(application);
}
static class User {
private String firstName;
private String middleName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "User{" +
"firstName='" + firstName + '\'' +
", middleName='" + middleName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}
}
step7
package org.springframework.boot;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import java.util.Map;
public class Step7 {
public static void main(String[] args) {
ApplicationEnvironment env = new ApplicationEnvironment();
SpringApplicationBannerPrinter printer = new SpringApplicationBannerPrinter(
new DefaultResourceLoader(),
new SpringBootBanner()
);
// 测试文字 banner
// env.getPropertySources().addLast(new MapPropertySource("custom", Map.of("spring.banner.location","banner1.txt")));
// 测试图片 banner
// env.getPropertySources().addLast(new MapPropertySource("custom", Map.of("spring.banner.image.location","banner2.png")));
// 版本号的获取
System.out.println(SpringBootVersion.getVersion());
printer.print(env, Step7.class, System.out);
}
}
Tomcat 基本结构
Server
└───Service
├───Connector (协议, 端口)
└───Engine
└───Host(虚拟主机 localhost)
├───Context1 (应用1, 可以设置虚拟路径, / 即 url 起始路径; 项目磁盘路径, 即 docBase )
│ │ index.html
│ └───WEB-INF
│ │ web.xml (servlet, filter, listener) 3.0
│ ├───classes (servlet, controller, service ...)
│ ├───jsp
│ └───lib (第三方 jar 包)
└───Context2 (应用2)
│ index.html
└───WEB-INF
web.xml
public static void main(String[] args) throws LifecycleException, IOException {
// 1.创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("tomcat");
// 2.创建项目文件夹, 即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
docBase.deleteOnExit();
// 3.创建 Tomcat 项目, 在 Tomcat 中称为 Context
Context context = tomcat.addContext("", docBase.getAbsolutePath());
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
ctx.addServlet("aaa", helloServlet).addMapping("/hello");
}
}, Collections.emptySet());
// 5.启动 Tomcat
tomcat.start();
// 6.创建连接器, 设置监听端口
Connector connector = new Connector(new Http11Nio2Protocol());
connector.setPort(8080);
tomcat.setConnector(connector);
}
WebApplicationContext springContext = getApplicationContext();
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
// ⬇️通过 ServletRegistrationBean 添加 DispatcherServlet 等
for (ServletRegistrationBean registrationBean :
springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
registrationBean.onStartup(ctx);
}
}
}, Collections.emptySet());
Spring Boot 是利用了自动配置类来简化了 aop 相关配置
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
spring.aop.auto=false
禁用 aop 自动配置@EnableAspectJAutoProxy
来开启了自动代理,如果在引导类上自己添加了 @EnableAspectJAutoProxy
那么以自己添加的为准@EnableAspectJAutoProxy
的本质是向容器中添加了 AnnotationAwareAspectJAutoProxyCreator
这个 bean 后处理器,它能够找到容器中所有切面,并为匹配切点的目标类创建代理,创建代理的工作一般是在 bean 的初始化阶段完成的简单说明一下,Spring Boot 支持两大类数据源:
PooledDataSource 又支持如下数据源
如果知道数据源的实现类类型,即指定了 spring.datasource.type
,理论上可以支持所有数据源,但这样做的一个最大问题是无法订制每种数据源的详细配置(如最大、最小连接数等)
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
mybatis.
前缀的配置项进行定制配置@MapperScan 注解的作用与 MybatisAutoConfiguration 类似,会注册 MapperScannerConfigurer 有如下区别
这里有同学有疑问,之前介绍的都是将具体类交给 Spring 管理,怎么到了 MyBatis 这儿,接口就可以被管理呢?
事务自动配置类有两个:
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
前者配置了 DataSourceTransactionManager 用来执行事务的提交、回滚操作
后者功能上对标 @EnableTransactionManagement,包含以下三个 bean
如果自己配置了 DataSourceTransactionManager 或是在引导类加了 @EnableTransactionManagement,则以自己配置的为准
假设已有第三方的两个自动配置类
@Configuration // ⬅️第三方的配置类
static class AutoConfiguration1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
@Configuration // ⬅️第三方的配置类
static class AutoConfiguration2 {
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
提供一个配置文件 META-INF/spring.factories,key 为导入器类名,值为多个自动配置类名,用逗号分隔
MyImportSelector=\
AutoConfiguration1,\
AutoConfiguration2
注意
- 上述配置文件中 MyImportSelector 与 AutoConfiguration1,AutoConfiguration2 为简洁均省略了包名,自己测试时请将包名根据情况补全
引入自动配置
@Configuration // ⬅️本项目的配置类
@Import(MyImportSelector.class)
static class Config { }
static class MyImportSelector implements DeferredImportSelector {
// ⬇️该方法从 META-INF/spring.factories 读取自动配置类名,返回的 String[] 即为要导入的配置类
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return SpringFactoriesLoader
.loadFactoryNames(MyImportSelector.class, null).toArray(new String[0]);
}
}
条件装配的底层是本质上是 @Conditional 与 Condition,这两个注解。引入自动配置类时,期望满足一定条件才能被 Spring 管理,不满足则不管理,怎么做呢?
比如条件是【类路径下必须有 dataSource】这个 bean ,怎么做呢?
首先编写条件判断类,它实现 Condition 接口,编写条件判断逻辑
static class MyCondition1 implements Condition {
// ⬇️如果存在 Druid 依赖,条件成立
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ClassUtils.isPresent("com.alibaba.druid.pool.DruidDataSource", null);
}
}
其次,在要导入的自动配置类上添加 @Conditional(MyCondition1.class)
,将来此类被导入时就会做条件检查
@Configuration // 第三方的配置类
@Conditional(MyCondition1.class) // ⬅️加入条件
static class AutoConfiguration1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
分别测试加入和去除 druid 依赖,观察 bean1 是否存在于容器
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.17version>
dependency>