第二章SpringBoot基础学习
文章目录
- SpringBoot依赖管理特性
- 依赖管理
- 开发导入starter场景启动器
- SpringBoot自动配置特性
- 自动配好Tomcat
- 自动配好SpringMVC
- 默认的包结构
- 各种配置拥有默认值
- 按需加载所有自动配置项
- SpringBoot注解底层注解
- @Configuration
- @Import导入组件
- @Conditional条件装配
- @ImportResource导入Spring配置文件
- @ConfigurationProperties配置绑定
- 自动配置
- @SpringBootApplication的源码
- @SpringBootConfiguration
- @ComponentScan
- @EnableAutoConfiguration
- 自动包规则原理
- @AutoConfigurationPackage
- 初始加载自动配置类
- @Import(AutoConfigurationImportSelector.class)
- @Import(AutoConfigurationImportSelector.class)
- 按需配置的例子
- 自动配置流程
SpringBoot依赖管理特性
依赖管理
我们在HelloWorld中导入的父项目依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version>
</parent>
spring-boot-starter-parent的父项目中的一个依赖如下:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.4.RELEASE</version>
</parent>
spring-boot-dependencies几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
- 导入spring-boot-starter-parent父项目是用来做依赖管理的,这样我们导入依赖无需关注版本号,自动版本仲裁
- 引入依赖默认都可以不写版本
- 引入非版本仲裁的jar,要写版本号。
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
-
可以修改默认版本号
-
查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
-
在当前项目里面重写配置,如下面的代码。
-
<properties><mysql.version>5.1.43</mysql.version>
</properties>
开发导入starter场景启动器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 见到很多 spring-boot-starter-* : *就某种场景
- web就是我们开发web应用的场景
- 只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
- 更多SpringBoot所有支持的场景
- 当我们觉得不够用,还可以自己创建starter启动器
- 见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
所有场景启动器最底层的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
SpringBoot自动配置特性
这里我们以我们导入的web场景下的starter为例子
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
自动配好Tomcat
- 引入Tomcat依赖。
- 配置Tomcat
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
自动配好SpringMVC
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(功能)
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.9.RELEASE</version><scope>compile</scope>
</dependency>
- 自动配好Web常见功能,如:字符编码问题
- SpringBoot帮我们配置好了所有web开发的常见场景
public static void main(String[] args) {//1、返回我们IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的组件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}
}
//部分输出结果
tomcatWebServerFactoryCustomizer
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
characterEncodingFilter--------设置字符编码的过滤器
localeCharsetMappingsCustomizer
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
multipartConfigElement
multipartResolver
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
org.springframework.aop.config.internalAutoProxyCreator
我们之前想解决中文乱码问题,需要我们自己配置字符编码过滤器,有了SpringBoot,我们都不需要设置
默认的包结构
- 主程序(也就是被我们@SpringBootApplication修饰的类)所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 自动代替我们之前Ioc容器xml文件中配置的自动扫描组件
- 无需以前的包扫描配置
- 想要改变扫描路径
- @SpringBootApplication(scanBasePackages=“com.lun”)
- 为什么不能直接通过@ComponentScan 指定扫描路径 因为我们的@SpringBootApplication()是一个合成注解
@SpringBootApplication(scanBasePackages="com.lsc")
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.lun")
各种配置拥有默认值
- 默认配置最终都是映射到某个类上,如:
MultipartProperties
#设置服务器的端口号
server.port=8080
#设置文件上传的最大大小
spring.servlet.multipart.max-file-size=10MB
配置文件的值最终会绑定每个类上,因为这个类会在容器中创建对象
按需加载所有自动配置项
- 我们的SpringBoot非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
- 但是不是所有的配置都会生效,至于原理需要了解相关注解的原理
我们的spring-boot-starter-web中存在spring-boot-starter依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
我们的spring-boot-starter中存在spring-boot-autoconfigure
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
SpringBoot注解底层注解
@Configuration
表示当前这个类是配置类,类似我们xml配置文件的作用
/*** @author lsc* #Description MyConfig* #Date: 2023/2/11 11:11*/
@Configuration(proxyBeanMethods = true)
public class MyConfig {@Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例public User user01(){User user = new User(1, "刘颂成");user.setCat(tomcat());return user ;}@Bean("tomcat")//如果不想以方法名为名称,可以自己自定义public Cat tomcat(){return new Cat("tomcat");}
}
- 配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
- 配置类本身也是组件
- proxyBeanMethods:代理bean的方法
-
Full(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认)
-
Lite(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的)
-
测试
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//1、返回我们IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的组件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}//3、从容器中获取组件Pet tom01 = run.getBean("tom", Pet.class);Pet tom02 = run.getBean("tom", Pet.class);System.out.println("组件:"+(tom01 == tom02));//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892MyConfig bean = run.getBean(MyConfig.class);System.out.println(bean);//如果@Configuration(proxyBeanMethods = true) 代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。//保持组件单实例User user = bean.user01();User user1 = bean.user01();System.out.println(user == user1);//trueUser user01 = run.getBean("user01", User.class);Cat tom = run.getBean("tomcat", Cat.class);System.out.println("用户的宠物:"+(user01.getPet() == tom));//true}
}
- 最佳实战
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
@Import导入组件
-
@Bean、@Component、@Controller、@Service、@Repository,它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能。
-
@ComponentScan表示扫描组件,来指定要扫描的包
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
public class MyConfig {@Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例public User user01(){User user = new User(1, "刘颂成");user.setCat(tomcat());return user ;}@Bean("tomcat")//如果不想以方法名为名称,可以自己自定义public Cat tomcat(){return new Cat("tomcat");}
}
- @Import自动导入对应的类,利用其无参构造方法创建一个Bean给容器进行管理
- @Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
测试类:
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//返回的是IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);String[] beanNamesForType = run.getBeanNamesForType(User.class);for (String s : beanNamesForType) {System.out.println(s);}DBHelper bean1 = run.getBean(DBHelper.class);System.out.println(bean1);}
}
//
com.lsc.springboot.pojo.User
user01
ch.qos.logback.core.db.DBHelper@73d6d0c
@Conditional条件装配
条件装配:满足Conditional指定的条件,则进行组件注入
- ConditionalOnBean,当容器存在某个Bean,才会进行注入以下的对象
- ConditionalOnMissingBean,当容器不存在某个Bean,才会进行注入以下的对象
用@ConditionalOnBean举例说明
/*** @author lsc* #Description MyConfig* #Date: 2023/2/11 11:11*/
@Configuration(proxyBeanMethods = true)
@ConditionalOnBean(name = "tomcat")//只有当有tom名字的Bean时,MyConfig类的Bean才能生效。
public class MyConfig {@Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例public User user01(){User user = new User(1, "刘颂成");user.setCat(tomcat());return user ;}
// @Bean("tomcat")//如果不想以方法名为名称,可以自己自定义public Cat tomcat(){return new Cat("tomcat");}
}
- 现在我们的容器中是不存在user01这个bean
- 对应的条件装配注解可以放在方法上也可以放在类上
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//返回的是IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);//查看我们IOC容器中Bean的组件名称boolean tomcat = run.containsBean("tomcat");System.out.println("名称为tomcat的存在"+tomcat);boolean user01 = run.containsBean("user01");System.out.println("名称为user01的bean存在"+user01);}
}
//输出结果
名称为tomcat的存在false
名称为user01的bean存在false
- 我们看到我们的tomcat这个bean不存在,所以连user01这个bean也没有注入容器
@ImportResource导入Spring配置文件
比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource登场。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.lsc.springboot.pojo.User" id="haha"><property name="id" value="2"></property><property name="name" value="sss"></property></bean><bean class="com.lsc.springboot.pojo.Cat" id="hehe"><property name="name" value="小猫"></property></bean>
</beans>
测试
public static void main(String[] args) {//1、返回我们IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);boolean haha = run.containsBean("haha");boolean hehe = run.containsBean("hehe");System.out.println("haha:"+haha);//trueSystem.out.println("hehe:"+hehe);//true
}
@ConfigurationProperties配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用
传统方式
public class getProperties {public static void main(String[] args) throws FileNotFoundException, IOException {Properties pps = new Properties();pps.load(new FileInputStream("a.properties"));Enumeration enum1 = pps.propertyNames();//得到配置文件的名字while(enum1.hasMoreElements()) {String strKey = (String) enum1.nextElement();String strValue = pps.getProperty(strKey);System.out.println(strKey + "=" + strValue);//封装到JavaBean。}}}
- 我们需要自己读取文件的内容,然后进行判断存入
Spring Boot一种配置配置绑定:
@ConfigurationProperties + @Component
假设有配置文件application.properties
mycar.brand=BYD
mycar.price=10000
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {private String brand;private Integer price;.......
}
- 因为只有被spring管理,才能拥有SpringBoot强大的功能
@RestController
public class HelloWorldController {@AutowiredCar car;@RequestMapping("/car")public Car car(){return car;}
SpringBoot另一种配置配置绑定
@EnableConfigurationProperties + @ConfigurationProperties
- 开启Car配置绑定功能
- 把这个Car这个组件自动注册到容器中
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
自动配置
被@SpringBootApplication表示为主类
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class,args);}
@SpringBootApplication的源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {...
}
重点分析@SpringBootConfiguration
,@EnableAutoConfiguration
,@ComponentScan
@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}
@Configuration
代表当前是一个配置类。
@ComponentScan
指定扫描哪些Spring注解。
@EnableAutoConfiguration
这个注解需要重点分析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}
重点分析@AutoConfigurationPackage
,@Import(AutoConfigurationImportSelector.class)
。
自动包规则原理
@AutoConfigurationPackage
标签名直译为:自动配置包,指定了默认的包规则。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};
}
- @Import({Registrar.class})利用Registrar给容器中导入一系列组件
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));}public Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));}}
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
初始加载自动配置类
@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
1、这个类中有一个这样的方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
2getAutoConfigurationEntry中调用了getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file correct.");return configurations;}
3 这个方法又调用了SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {try {Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result = new LinkedMultiValueMap();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Entry<?, ?> entry = (Entry)var6.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;for(int var11 = 0; var11 < var10; ++var11) {String factoryImplementationName = var9[var11];result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}
发现一个多次出现的文件:spring.factories,全局搜索它
spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:
@Import(AutoConfigurationImportSelector.class)
-
AutoConfigurationImportSelector类中利用
getAutoConfigurationEntry(annotationMetadata);
给容器中批量导入一些组件 -
getAutoConfigurationEntry方法中通过调用
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取到所有需要导入到容器中的配置类-
SpringFactoriesLoader利用工厂加载
Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);
得到所有的组件-
从
META-INF/spring.factories
位置来加载一个文件。 -
默认扫描我们当前系统里面所有
META-INF/spring.factories
位置的文件
-
-
spring-boot-autoconfigure-2.3.4.RELEASE.jar
包里面也有META-INF/spring.factories
# 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
# spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
...
虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration
按照条件装配规则(@Conditional
),最终会按需配置。
springboot所有的自动配置都是在启动的时候扫描并加载,扫描了spring.properties配置文件,所有的自动配置类都在这里面,但是不定生效,因为要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器我们自动装配就会生效,然后就配置成功
按需配置的例子
AopAutoConfiguration
类:
@Configuration(proxyBeanMethods = false
)
@ConditionalOnProperty(prefix = "spring.aop",name = "auto",havingValue = "true",matchIfMissing = true
)
public class AopAutoConfiguration {public AopAutoConfiguration() {}...
}
- prefix为配置文件中的前缀,
- name为配置的名字
- havingValue是与配置的值对比值,当两个值相同返回true,配置类生效.
- matchIfMissing表示如果没有这么配置的默认值
自动配置流程
以DispatcherServletAutoConfiguration
的内部类DispatcherServletConfiguration
为例子:
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {// Detect if the user has created a MultipartResolver but named it incorrectlyreturn resolver;//给容器中加入了文件上传解析器;
}
- 给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
- 方法名为multipartResolver ,SpringMVC multipartResolver防止有些用户配置的文件上传解析器不符合规范
SpringBoot默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先。
总结:
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
面试官问你你可以这样说,springboot是通过main方法下的SpringApplication.run方法启动的,启动的时候他会调用refshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式注册bean,还会它是通过启动类的SpringBootApplication注解进行开始解析的,他会根据EnableAutoConfiguration开启自动化配置,里面有个核心方法ImportSelect选择性的导入,根据loadFactoryNames根据classpath路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置,他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解,先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器
相关文章:

第二章SpringBoot基础学习
文章目录SpringBoot依赖管理特性依赖管理开发导入starter场景启动器SpringBoot自动配置特性自动配好Tomcat自动配好SpringMVC默认的包结构各种配置拥有默认值按需加载所有自动配置项SpringBoot注解底层注解ConfigurationImport导入组件Conditional条件装配ImportResource导入Sp…...

B - Build Roads (最小生成树 + 打表)
https://vjudge.net/problem/Gym-103118B/origin 在猫的国度里,有n个城市。猫国国王想要修n -1条路来连接所有的城市。第i市有一家ai经验价值的建筑公司。要在第i市和第j市之间修建公路,两个城市的建筑公司需要相互合作。但是,在修路的过程中…...
k8s管理工具
k8s管理工具 文章目录k8s管理工具Kuboard(💕17.3k)KubeOperator(💕4.6k)Rainbond(💕3.8k)KubeSphere(💕12k)Kuboard(&…...

Cannot start compiler The output path is not specified for module mystatic(已解决)
1.背景:今天在idea上写了一些代码,右键run竟然跑不起来了,而且右下角的Event Log还报错。报错内容如下图:2.报错原因:项目代码和编译器的输出路径不在一块,导致idea无法找到模块的output path(输…...

python入门应该怎么学习
国外Python的使用率非常高,但在国内Python是近几年才火起来,Python正处于高速上升期市场对于Python开发人才的需求量急剧增加,学习Python的前景比较好。 Python应用领域广泛,意味着选择Python的同学在学成之后可选择的就业领域有…...

不懂命令, 如何将代码托管到Gitee上
1.注册码云注册地址 : https://gitee.com2. 新建仓库第一步 : 创建仓库第二步 : 给仓库起名字创建好仓库后, 我们就有了一个网络上的仓库 : 3. 将网络上的仓库克隆到本地在克隆仓库之前, 我们需要先在电脑上安装以下两个工具 >>这两个软件一定要按顺序安装, 先安装第一个…...

Mysql常见面试题总结
1、什么是存储引擎 存储引擎指定了表的类型,即如何存储和索引数据,是否支持事务,同时存储引擎也决定了表在计算机中的存储方式。 2、查看数据库支持哪些存储引擎使用什么命令? -- 查看数据库支持的存储引擎 show engines; 或者 …...

python第一周作业
作业1:1、PPT上五个控制台界面2、要求定义两个数,并且交换它们的值(请使用多种方式,越多越好)作业1作业2:判断一个数,是否是2的指数2的指数0000 0010 0000 00010000 0100 0000 00110000 1000 00…...

FLoyd算法的入门与应用
目录 一、前言 二、FLoyd算法 1、最短路问题 2、Floyd算法 3、Floyd的特点 4、Floyd算法思想:动态规划 三、例题 1、蓝桥公园(lanqiaoOJ题号1121) 2、路径(2021年初赛 lanqiaoOJ题号1460) 一、前言 本文主要…...

303. 区域和检索 - 数组不可变
303. 区域和检索 - 数组不可变 给定一个整数数组 nums,处理以下类型的多个查询: 计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left < right 实现 NumArray 类: NumArray(int[] num…...

Spring Cloud融合Nacos配置加载优先级 | Spring Cloud 8
一、前言 Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置: A:通过内部相关规则(应用名、扩展名、profiles)自动生成相关的 Data Id 配置B:通过 spring.cloud.nacos.config.extension-configs的方式支持…...

LeetCode 236.二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖…...
awk简单实例(持续更新中)
一 概述 awk命令是一种分析和处理文本文件的编程工具。它的功能非常强大,是Linux/Unix系统中最常用的过滤工具。 awk内建变量: NF 整个数据行(即$0)拥有的字段总数 NR 当前awk所处理的数据行的编号 $0 当前awk所处理的数据行 $1 数据行的第1个字段 $2 数…...

react动态路由组件的封装
react动态路由组件的封装 我这篇比较全面 首先下载包 npm i react-router-dom5 这里为什么要用5的版本为啥不用最新的,原因在于老版本跟新版本写法不一样 老版本 import { HashRouter, Route, Switch, Redirect } from react-router-dom;render() {return (<Ha…...

Vue项目中引入高德地图步骤详解
高德地图API官网:高德开放平台 | 高德地图API。 目录 一、案例效果 二、开发准备 1. 注册高德开放平台账号 2. 创建应用添加 key 值 三、项目中使用地图组件 1. npm 获取高德地图 API 2.在项目中新建 MapContainer.vue 文件,用作地图组件。 3.在…...

软件测试用例篇(2)
功能测试界面测试兼容性测试安全测试易用性测试性能测试 针对有需求的案例来设计测试用例:邮箱注册,部分测试用例 https://zay1xofb7z6.feishu.cn/mindnotes/bmncnKD5Ak6GSZl3PRlWDgF9z3g#mindmap 一)等价类: 场景需求:姓名长度是6-200位,那么如何进行设…...
leetcode题解-27. Remove Element
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…...

【fly-iot飞凡物联】(4):在linux系统上搭建arduino环境,可以使用离线包,导入到arduino上即可。
目录前言1,关于2,然后就可以找到ESP32,ESP8266的主版3,方法2,github下载,然后手动添加到ide中吧4,总结前言 本文的原文连接是: https://blog.csdn.net/freewebsys/article/details/108971807 未…...

java实例解析类图中【关联、组合和聚合】的区别
总目录链接==>> AutoSAR入门和实战系列总目录 文章目录 聚合Composition聚合与组合的区别关联是两个独立类之间的关系,它通过它们的对象建立关联。关联可以是一对一、一对多、多对一、多对多。在面向对象的编程中,一个对象与另一个对象通信以使用该对象提供的功能和服…...

基于m-p条件查询代码生成
目录 起因 演示 使用 0.自定义注解 1.定义一个dto的条件查询类 2.调用主程序 效果图 小结 代码 注解 Dto类 完整代码 起因 最近两天一直写后台管理统计的增删改查(很少写增删改查,所以不是很熟练),几乎每个表都要涉及到条件查询的业务…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...