当前位置: 代码迷 >> 综合 >> 【SpringBoot】@SpringBootApplication
  详细解决方案

【SpringBoot】@SpringBootApplication

热度:96   发布时间:2023-12-22 23:03:47.0

@SpringBootApplication相当于下面的3个注解


@SpringBootConfiguration:
进入SpringBootConfiguration源码可以看到:
在这里插入图片描述

@SpringBootConfiguration就相当于是@Configuration。代表当前是一个配置类


@ComponentScan(“com.atguigu.boot”):
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来, 想要改变扫描路径:@SpringBootApplication(scanBasePackages=“com.atguigu”)或者ComponentScan(“com.atguigu.boot”)


@EnableAutoConfiguration:
主要由以下两个注解实现功能
在这里插入图片描述

@AutoConfigurationPackage:

在这里插入图片描述
在这里插入图片描述

自动配置包,指定了默认的包规则

@Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入Registrar
public @interface AutoConfigurationPackage {
    }	//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。//这是Registrar的实现:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    @Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {
    return Collections.singleton(new PackageImports(metadata));}}//其中new PackageImports(metadata).getPackageNames()就是得到MainApplication所在的包名,将包名封装到数组中,之后注册进去(也就是将主类所在的包中的组件批量注册),这就解释了为什么默认的包路径是MainApplication所在的包
@Import(AutoConfigurationImportSelector.class)

1.@Import注解的源码中的selectImports,确定到底要给容器中导入哪些组件,其返回的String[]是由getAutoConfigurationEntry(annotationMetadata)决定的。
在这里插入图片描述

2、调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类

在这里插入图片描述
List configurations:
在这里插入图片描述
利用Spring的工厂加载器 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件

在这里插入图片描述在这里插入图片描述

4、从META-INF/spring.factories位置来加载一个资源文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
在这里插入图片描述

有些位置的META-INF中是没有spring.factories的

在这里插入图片描述
主要是扫描spring-boot-autoconfigure-2.3.4.RELEASE.jar中的META-INF/spring.factories,SpringBoot兼容的全场景的自动配置都在此处列举,共127个。

在这里插入图片描述
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
符合条件装配规则(@Conditional)才会导入。

spring-boot-autoconfigure-2.3.4这个包中有我们需要的全场景配置:
在这里插入图片描述
以AOP为例:
需要判断:文件中是否存在spring.aop这个配置,且spring.aop.auto的值是true,最后一个matchIFMissiing会认为就算没有将这个值配置为true,也会默认是true。
在这里插入图片描述
对于AspectJAutoProxyingConfiguration这个类,可以看到上面的 @ConditionalOnClass(Advice.class)注释 ,说明只有当Advice.class存在时,这个类中的一些配置才会生效。
在这里插入图片描述

对于ClassProxyingConfiguration这个类,可以看到
@ConditionalOnMissingClass(“org.aspectj.weaver.Advice”) 意思是如果没有org.aspectj.weaver.Advice这个类,下面的配置才会生效
@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “true”,matchIfMissing = true)意思是必须有spring.aop这个配置项,且spring.aop.name属性必须是proxy-target-class,havingValue 这个配置项必须是true,如果不是true也会默认是true。
上面的条件这个类都是满足的,所以这个类中的配置是生效的。
但是这个类只是简单的AOP功能,也就是说这个AOP必须有接口有实现类才可以创建代理对象。
在这里插入图片描述


以cache为例:
在这里插入图片描述
@ConditionalOnClass(CacheManager.class)
首先确认容器中有没有CacheManager.class存在,CacheManager.class是在spring-context这个包中的类,此包是整个spring环境中的核心包,所以肯定是存在的
@ConditionalOnBean(CacheAspectSupport.class)
判断容器中有没有CacheAspectSupport.class这种类型的组件(上面的例子中都是以名称判断的,也可以通过其他关键点判断)
通过这行代码可以判断出容器中是没有CacheAspectSupport.class这种类型的组件的存在的

String[] beanNamesForType = run.getBeanNamesForType(CacheAspectSupport.class);
System.out.println("======"+beanNamesForType.length);

最终输出结果为0,所以不满足@ConditionalOnBean(CacheAspectSupport.class),所以这个类中的所有配置都没有生效,后面的条件已经不需要去看了。
@ConditionalOnMissingBean(value = CacheManager.class, name = “cacheResolver”)
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })


以web中的servlet中DispatcherServletAutoConfiguration为例:
在这里插入图片描述
@ConditionalOnWebApplication(type = Type.SERVLET):判断当前是否是一个原生的serrvlet应用,因为springboot2现在支持两种web模式开发,一种是响应式编程,一种是原生的。servlet。
@ConditionalOnClass(DispatcherServlet.class):判断是否导入DispatcherServlet.class这类
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)