Why use spring.factories for Spring Boot auto-configuration instead of annotations?

后端 未结 3 1760
感情败类
感情败类 2020-12-29 07:29

The documentation states:

Developing auto-configuration and using conditions

If you work in a company that develops shared libraries, or i

3条回答
  •  情歌与酒
    2020-12-29 08:08

    When SpringBoot app is starting, it will not scan all the classes in jars, So SpringBoot starter should specify which classes are auto-configured. For example, in spring-boot-2.0.4.RELEASE, it initializes like this:

    @SpringBootApplication
    public class MyApplication {
        public static void main(String[] args) {
           //1. method run will call the construtor below
            SpringApplication.run(MyApplication.class, args);
        }
    }
    
        public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            this.webApplicationType = deduceWebApplicationType();
            //2. find all the classes whose key is ApplicationContextInitializer in spring.factories and initialize them 
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    
    ...
        private  Collection getSpringFactoriesInstances(Class type,
                Class[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // Use names and ensure unique to protect against duplicates
            Set names = new LinkedHashSet<>(
                    //3. use current thread classcloader to load resources in the classpath
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }
    
    //SpringFactoriesLoader.java
    public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            // 3.1  first find the configuration file
            return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
        }
    
    private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
            ...
            try {
                Enumeration urls = (classLoader != null ?
                //  public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 
                //4. spring.factories file is defined here
                        classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                result = new LinkedMultiValueMap<>();
                ...
        }
    

提交回复
热议问题