好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

springboot 加载 META-INF/spring.factories

用户应用程序Application

?

1

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

SpringApplication类

?

1

2

3

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {

   return run( new Class<?>[] { primarySource }, args);

  }

?

1

2

3

4

// 这里Class是数组

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {

   return new SpringApplication(primarySources).run(args);

  }

?

1

2

3

public SpringApplication(Class<?>... primarySources) {

   this ( null , primarySources);

  }

?

1

2

3

4

5

6

7

8

9

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,返回数据

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

/** 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注入到容器当中

?

1

2

3

4

5

6

7

8

9

10

11

12

@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这个注解里面的东西

?

1

2

3

4

5

6

7

8

9

@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这个类:

这个类里面有一个方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

  * 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文件去进行加载的。

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

原文链接:https://kingkong.blog.csdn.net/article/details/104491907

查看更多关于springboot 加载 META-INF/spring.factories方式的详细内容...

  阅读:18次