springboot 加载 META-INF/spring.factories方式

目录
  • springboot 加载 META-INF/spring.factories
    • 用户应用程序Application
  • 建立META-INF/spring.factories文件的意义何在
    • 平常我们如何将Bean注入到容器当中

springboot 加载 META-INF/spring.factories

用户应用程序Application

ConfigurableApplicationContext context = SpringApplication.run(NacosSpringBootYamlApplication.class, args);

SpringApplication类

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  return run(new Class<?>[] { primarySource }, args);
 }
// 这里Class是数组
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  return new SpringApplication(primarySources).run(args);
 }
public SpringApplication(Class<?>... primarySources) {
  this(null, primarySources);
 }
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 这里就是SpringMvcApplication的实例
  this.webApplicationType = WebApplicationType.deduceFromClasspath();// deduce(推断)web类型(servlet、reactive、NoWeb)
  setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 这里会处理加载所有的spring.factories文件的内容到缓存 找到*META-INF/spring.factories*中声明的所有ApplicationContextInitializer的实现类并将其实例化
  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //找到*META-INF/spring.factories*中声明的所有ApplicationListener的实现类并将其实例化
  this.mainApplicationClass = deduceMainApplicationClass(); //获得当前执行main方法的类对象,这里就是SpringMvcApplication的实例
 }

具体加载该classLoader下的所有spring.factories到缓存

如果缓存已经存在,则直接根据key,返回数据

/** key:是spring.factories的key    value:是根据key分组,把同个key的不同value放到list里面 */
 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  MultiValueMap<String, String> result = cache.get(classLoader);
  if (result != null) { //已经处理过了  直接返回
   return result;
  }
//url: // file:/C:/Users/kongqi/.m2/repository/org/springframework/spring-beans/5.1.9.RELEASE/spring-beans-5.1.9.RELEASE.jar!/META-INF/spring.factories
  try { //得到classloader下的所有jar包中的spring.factories的文件
   Enumeration<URL> urls = (classLoader != null ?
     classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
   result = new LinkedMultiValueMap<>();
   while (urls.hasMoreElements()) {
    URL url = urls.nextElement();
    UrlResource resource = new UrlResource(url);
    Properties properties = PropertiesLoaderUtils.loadProperties(resource); // 得到spring.factories的内容
    for (Map.Entry<?, ?> entry : properties.entrySet()) { // key: spring.factories的key  value: spring.factories的value
     String factoryClassName = ((String) entry.getKey()).trim(); // spring.factories的key
     for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {//value根据逗号,分隔
      result.add(factoryClassName, factoryName.trim()); //factoryClassName其实就是spring.factories的key   由于value是List类型 MultiValueMap value有多个
     }
    }
   }
   cache.put(classLoader, result);
   return result;
  }
  catch (IOException ex) {
   throw new IllegalArgumentException("Unable to load factories from location [" +
     FACTORIES_RESOURCE_LOCATION + "]", ex);
  }
 }

流程图

建立META-INF/spring.factories文件的意义何在

平常我们如何将Bean注入到容器当中

@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
    @Autowired
    HelloProperties helloProperties;
    @Bean
    public HelloService helloService() {
        HelloService service = new HelloService();
        service.setHelloProperties( helloProperties  );
        return service;
    }
}

一般就建立配置文件使用@Configuration,里面通过@Bean进行加载bean

或者使用@Compont注解在类上进行类的注入

注意:

在我们主程序入口的时候:

@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 {

里面注解@EnableAutoConfiguration

@ComponentScan注解指扫描@SpringBootApplication注解的入口程序类所在的basepackage下的

所有带有@Component注解的bean,从而注入到容器当中。

但是

如果是加入maven坐标依赖的jar包,就是项目根目录以外的Bean是怎么添加的??

这个时候注解@EnableAutoConfiguration的作用就来了

导入了AutoConfigurationImportSelector这个类:

这个类里面有一个方法

    /**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using {@link SpringFactoriesLoader} with
     * {@link #getSpringFactoriesLoaderFactoryClass()}.
     * @param metadata the source metadata
     * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
     * attributes}
     * @return a list of candidate configurations
     */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                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;
    }

@EnableAutoConfiguration注解来注册项目包外的bean。而spring.factories文件,则是用来记录项目包外需要注册的bean类名

为什么需要spring.factories文件,

因为我们整个项目里面的入口文件只会扫描整个项目里面下的@Compont @Configuration等注解

但是如果我们是引用了其他jar包,而其他jar包只有@Bean或者@Compont等注解,是不会扫描到的。

除非你引入的jar包没有Bean加载到容器当中

所以我们是通过写/META-INF/spring.factories文件去进行加载的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • spring boot加载资源路径配置和classpath问题解决

    1.spring boot默认加载文件的路径: /META-INF/resources/ /resources/ /static/ /public/ 我们也可以从spring boot源码也可以看到: private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classp

  • SpringBoot加载静态资源的方式

    在SpringBoot中加载静态资源和在普通的web应用中不太一样.默认情况下,spring Boot从classpath下一个叫/static(/public,/resources或/META-INF/resources)的文件夹或从ServletContext根目录提供静态内容.下面我们来写个例子看一下就会一目了然了:首先看一下项目的目录结构: 我们在resources下面的templates目录下建一个home.html的文件,完整目录为:src/main/resources/templa

  • Spring Boot加载配置文件的完整步骤

    前言 本文针对版本2.2.0.RELEASE来分析SpringBoot的配置处理源码,通过查看SpringBoot的源码来弄清楚一些常见的问题比如: SpringBoot从哪里开始加载配置文件? SpringBoot从哪些地方加载配置文件? SpringBoot是如何支持yaml和properties类型的配置文件? 如果要支持json配置应该如何做? SpringBoot的配置优先级是怎么样的? placeholder是如何被解析的? 带着我们的问题一起去看一下SpringBoot配置相关的源

  • springboot 加载 META-INF/spring.factories方式

    目录 springboot 加载 META-INF/spring.factories 用户应用程序Application 建立META-INF/spring.factories文件的意义何在 平常我们如何将Bean注入到容器当中 springboot 加载 META-INF/spring.factories 用户应用程序Application ConfigurableApplicationContext context = SpringApplication.run(NacosSpringBoo

  • SpringBoot加载配置文件的实现方式总结

    目录 一.简介 二.代码实践 2.1.通过@value注解实现参数加载 2.2.通过@ConfigurationProperties注解实现参数加载 2.3.通过@PropertySource注解实现配置文件加载 2.4.通过自定义环境处理类,实现配置文件的加载 2.5.最后,我们来介绍一下yml文件读取 三.小结 一.简介 在实际的项目开发过程中,我们经常需要将某些变量从代码里面抽离出来,放在配置文件里面,以便更加统一.灵活的管理服务配置信息.比如,数据库.eureka.zookeeper.r

  • 解决SpringBoot加载application.properties配置文件的坑

    SpringBoot加载application.properties配置文件的坑 事情的起因是这样的 一次,本人在现场升级程序,升级完成后进行测试,结果接口调用都报了这么个错误: 大概意思是https接口需要证书校验,这就奇怪了,项目启动加载的是包外的application.properties配置文件,配置文件里没有配置使用https啊.本人马上检查了下包内的application.properties配置文件,发现包内确实配置了https相关的配置项: 明明包外的配置文件优先级高于包内的,为

  • SpringBoot加载外部依赖过程解析

    这篇文章主要介绍了SpringBoot加载外部依赖过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景 公司一个项目的大数据平台进行改造,之前使用Structured Streaming作为实时计算框架,需要替换为替换为Kafka Streams,并使用SpringBoot包装,使其可以纳入微服务体系. 然而由于之前并没有接触过SpringFramework相关技术,并且项目工期较为紧张,因此只好花了2天时间看了看Spring和Spri

  • 详解使用Vue.Js结合Jquery Ajax加载数据的两种方式

    整理文档,搜刮出一个使用Vue.Js结合Jquery Ajax加载数据的两种方式的代码,稍微整理精简一下做下分享. 废话不多说,直接上代码 html代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>demo</title> <script src="js/jquery.js"

  • jquery加载图片时以淡入方式显示的方法

    本文实例讲述了jquery加载图片时以淡入方式显示的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title></title> </head> <script type="text/java

  • springboot加载复杂的yml文件获取不到值的解决方案

    目录 springboot加载yml文件获不到值 获取不到yml配置文件指定的值 springboot加载yml文件获不到值 今天使用spring boot读取yml文件,这种多层嵌套的竟然无法读取到(value注解spring.redis.pool.max.wait),即便加上全名也不行,然后网上搜到的内容也未曾满意,很多文章内容都是一样且重复的.最后放弃了查找,突发奇想之下解决了这个问题. 本文旨在如何读取多层嵌套的yml文件,希望能帮到众位. 以下是代码: package com.boot

  • SpringBoot加载读取配置文件过程详细分析

    目录 配置文件的读取顺序 多坏境的配置文件 个性化配置 自定义配置文件名称和路径 加载yml文件 springboot默认读取的配置文件名字是:“application.properties”和“application.yml”,默认读取四个位置的文件:根目录下.根目录的config目录下.classpath目录下.classpath目录里的config目录下: 配置文件的读取顺序 根目录/config/application.properties 根目录/config/application.

  • springboot加载命令行参数ApplicationArguments的实现

    目录 一.介绍 二.通过应用程序参数获取配置 1. 通过bean获取应用程序参数 2. 通过@Value注解获取 三.源码解读 - 封装应用程序参数 1. DefaultApplicationArguments 2. Source类 3. SimpleCommandLinePropertySource 4. SimpleCommandLineArgsParser 5. CommandLinePropertySource 6. PropertySource 四.源码解读 - 为什么可以通过@Val

  • 基于vue中css预加载使用sass的配置方式详解

    1.安装sass的依赖包 npm install --save-dev sass-loader //sass-loader依赖于node-sass npm install --save-dev node-sass 2.在build文件夹下的webpack.base.conf.js的rules里面添加配置,如下红色部分 { test: /\.sass$/, loaders: ['style', 'css', 'sass'] } <span style="color:#454545;"

随机推荐