当前位置: 首页 > news >正文

wordpress 开启日志南宁网站优化公司电话

wordpress 开启日志,南宁网站优化公司电话,好的企业管理网站,wordpress搜索调用文章目录 前言一、SpringBoot优势概要二、SpringBoot自动配置1. ☠注意☠2.自动配置详解 三、Starter(场景启动器)原理总结 前言 本文详细解析面试重点—SpringBoot自动配置原理、场景启动器原理,深入源码,直接上干货、绝不拖泥带…

文章目录

  • 前言
  • 一、SpringBoot优势概要
  • 二、SpringBoot自动配置
    • 1. ☠注意☠
    • 2.自动配置详解
  • 三、Starter(场景启动器)原理
  • 总结


前言

本文详细解析面试重点—SpringBoot自动配置原理、场景启动器原理,深入源码,直接上干货、绝不拖泥带水。


一、SpringBoot优势概要

一句话:约定大于配置,简化Spring的简化

  • 内嵌Web服务器
  • 环境启动器starter的使用,简化构建配置
  • 无需编写繁琐XML文件

二、SpringBoot自动配置

1. ☠注意☠

首先,要明确自动配置和自动装配的区别。
自动装配是SpringBoot的概念,是通过条件注解和配置元数据的方式,根据应用程序的依赖和环境,自动为应用程序进行配置。
自动装配是Spring的概念,是Spring框架通过依赖注入(Dependency Injection)机制来实现的,它通过自动根据类型或名称匹配来自动关联和装配Bean。

!!!!网络上有很多文章、视频张嘴就是SpringBoot的自动装配,这些基本不用看了,属实有些乐色!

2.自动配置详解

  • 创建一个SpringBoot2项目用作示例:

主配置类:

package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootTestApplication {public static void main(String[] args) {SpringApplication.run(SpringBootTestApplication.class, args);}}

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><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.0</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>SpringBoot-Test</artifactId><version>0.0.1-SNAPSHOT</version><name>SpringBoot-Test</name><description>SpringBoot-Test</description><properties><java.version>8</java.version></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-test</artifactId><scope>test</scope></dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
  • 项目结构分析

通过主配置类可以看出SpringBoot的最重要注解是@SpringBootApplication
通过POM文件可知SpringBoot项目的父项目是spring-boot-starter-parent

  • @SpringBootApplication详解

在IDEA中按住CTRL键进入@SpringBootApplication注解:

package org.springframework.boot.autoconfigure;import ...;@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 {@AliasFor(annotation = EnableAutoConfiguration.class)Class<?>[] exclude() default {};...... 
}

可以看到@SpringBootApplication主要由:
@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan注解构成

我们逐个分析以上三个注解:

1. @SpringBootConfiguration注解
源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

可以看出该注解由@Configuration注解和其他注解组成,所以,该注解的作用和@Configuration注解作用相似,代表当前是一个SpringBoot配置类。

2. @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 {};
}

可以看出@AutoConfigurationPackage通过内部的@Import注解向IOC容器中导入了类: Registrar.class

Registrar.class源码:

 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));}}

发现,@AutoConfigurationPackage利用Registrar给容器中导入一系列组件,将主配置类所在包下的所有组件导入容器中。

  • @Import({AutoConfigurationImportSelector.class})源码:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered{.......
}

发现AutoConfigurationImportSelector实现了DeferredImportSelector接口,这就不得不提一下@Import注解的使用方式了,可以看看这篇文章:
@Import三种使用方式
@Import作用是向IOC容器中导入组建,其中有一种就是实现ImportSelector接口,并实现其中的selectImports方法,该方法的作用是返回一个由想要导入IOC容器的对象组成的数组。

查看AutoConfigurationImportSelector中实现的selectImports方法:

public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}

发现其中调用了getAutoConfigurationEntry方法,继续跟进:

    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);}}

很明显,getAutoConfigurationEntry方法又调用了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 is correct.");return configurations;}

发现getCandidateConfigurations调用了SpringFactoriesLoader的loadFactoryNames方法:

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoader == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}

此方法又调用了loadSpringFactories方法:

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {HashMap result = new HashMap();try {Enumeration urls = classLoader.getResources("META-INF/spring.factories");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[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;for(int var12 = 0; var12 < var11; ++var12) {String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName, (key) -> {return new ArrayList();})).add(factoryImplementationName.trim());}}}result.replaceAll((factoryType, implementations) -> {return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));});cache.put(classLoader, result);return result;} catch (IOException var14) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);}}}

可以看出其从META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件。经过一层层返回之后,使用@Import注解导入到IOC容器
3. @ComponentScan注解

@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}

此注解作用是默认扫描主配置类所在包及其子包中的@Component注解及其衍生注解

三、Starter(场景启动器)原理

1. 什么是场景启动器

Spring Boot场景启动器(Starter)是Spring Boot框架提供的一种便利机制,用于快速引入和配置特定场景下所需的依赖项。每个场景启动器都是一个独立的Maven项目,它提供了一组相关的依赖和配置,以便简化和加速特定场景下的应用程序开发。

2. 场景启动器特点

  • 集成依赖项:每个场景启动器都定义了一组相关的依赖项。这些依赖项被认为在特定场景中非常有用,比如Web开发、数据库访问、消息队列等等。通过使用场景启动器,开发者可以快速引入和配置所需的依赖项,而无需手动添加和管理这些依赖项。
  • 自动配置:场景启动器还提供了一些默认的自动配置,旨在简化特定场景下的配置工作。这些自动配置通常基于Spring Boot的条件注解和配置元数据机制,根据应用程序的依赖和环境来自动配置必要的组件和选项。通过使用场景启动器,开发者可以快速启动和运行基本的应用程序,而无需过多关注和编写配置代码。
  • 统一引入和管理:场景启动器通过简化和标准化依赖项的引入和配置,提供了一种统一的方式来解决常见的开发场景。开发者可以通过在项目的pom.xml文件中添加相应的场景启动器依赖,一次性引入和管理所有相关的依赖项,从而简化了项目的依赖管理和版本冲突的问题。

3. 以spring-boot-starter-web为示例

import ....;@Configuration(proxyBeanMethods = false
)
@ConditionalOnWebApplication(type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {public static final String DEFAULT_PREFIX = "";public static final String DEFAULT_SUFFIX = "";private static final String SERVLET_LOCATION = "/";public WebMvcAutoConfiguration() {}@Bean@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter",name = {"enabled"})public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter();}@Bean@ConditionalOnMissingBean({FormContentFilter.class})@ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter",name = {"enabled"},matchIfMissing = true)public OrderedFormContentFilter formContentFilter() {return new OrderedFormContentFilter();}static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy {private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP";private final ContentNegotiationStrategy delegate;OptionalPathExtensionContentNegotiationStrategy(ContentNegotiationStrategy delegate) {this.delegate = delegate;}public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, 0);return skip != null && Boolean.parseBoolean(skip.toString()) ? MEDIA_TYPE_ALL_LIST : this.delegate.resolveMediaTypes(webRequest);}}static class ResourceChainResourceHandlerRegistrationCustomizer implements WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer {private final Resources resourceProperties;ResourceChainResourceHandlerRegistrationCustomizer(Resources resourceProperties) {this.resourceProperties = resourceProperties;}

以上文中的SpringBoot自动配置为基础,可知SpringBoot会扫描我们引入的依赖中的META-INF目录下的spring.factories文件中以EnableAutoConfiguration为key的值,将其加入到IOC容器中,但是并不是所有的对象都会加入到IOC容器中,应为这些starter的主配置类中都会有@Conditional注解来指定约束条件:

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下

4. starter整体结构
xxxAutoConfiguration:starter中的主配置类,其中定义了特定条件和默认配置文件的指定
xxxProperties:默认文件,可以在我们使用starter的时候进行配置覆盖,这里重点体现了springboot的约定大于配置。

总结

SpringBoot 使用@EnableAutoConfiguration开启自动配置功能,通过@Import注解加载实现了ImportSelector接口的类并最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖。

http://www.qdjiajiao.com/news/11908.html

相关文章:

  • 做品牌网站seo线下培训班
  • 旅游公司网站开发衡阳seo
  • 网站建设文书百度网站大全首页
  • wordpress 千万数据郑州seo网站有优化
  • 上海市建上海市建设安全协会网站今天最新消息
  • 网站建设中两个变量合并操作竞价推广的企业
  • 旅游景区网站建设百度查询最火的关键词
  • 哪家公司做网站便宜百度网址导航
  • 网站seo优化技术入门百度网站优化排名
  • 专业网站建设的网站做成app
  • 重庆手机网站推广资料营销平台建设
  • 福州专业建站公司关键词排名点击软件怎样
  • 网站设计页面如何做居中如何引流与推广
  • 电商网站建设效果seo优化中以下说法正确的是
  • 阿里巴巴网站分类板块做全屏知识搜索引擎
  • 上海这边敲墙拆旧做啥网站的比较多怎么建网站
  • 网站域名建设费进什么科目谷歌浏览器安卓下载
  • 又快又好自助建站系统百度投诉中心人工电话号码
  • 广西seo优化荆州seo推广
  • 大庆市建设网站武汉十大技能培训机构
  • 叫别人做网站权重被转移了百度热搜的含义
  • 淘宝客网站做app营销推广策略
  • 犀牛云做网站怎么这么贵成品网站货源1688在线
  • 商城网站建设计划书sem是什么显微镜
  • 网站建设出售网站建设公司业务
  • 网站如何能让百度收录世界足球排名前100名
  • h5搭建南宁百度seo优化
  • 苏州高端网站制作官网营销网站定制
  • 响应式网站建设代理上海百度
  • 怎么修改网站图片在线外链发布工具