0


SpringApplication对象的构建及spring.factories的加载时机

构建SpringApplication对象源码:
1、调用启动类的main()方法,该方法中调用SpringApplication的run方法。

@SpringBootApplication
public class SpringbootdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootdemoApplication.class, args);
    }
}

2、调用SpringApplication的run()方法的重载方法,在发方法内构建了SpringApplication对象

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

3、构建SpringApplication对象。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        //resourceLoader为null
        this.resourceLoader = resourceLoader;
        //PrimarySources(即启动类)一定不能为null
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //初始化primarySources属性
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //从Classpath中推断Web应用类型。
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrapRegistryInitializers = new ArrayList<>(
                getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

构建过程:

接下来我们来详细研究一下上述过程。在构建SpringApplication对象过程中,此时resourceLoader
为null,primarySources一定不为空且需要初始化为启动类SpringbootdemoApplication
。从Classpath中推断出Web应用类型并初始化webApplicationType,通过getSpringFactoriesInstances()获取Spring工厂实例来初始化bootstrapRegistryInitializers,initializers(List<ApplicationContextInitializer<?>>应用程序上下文初始化器列表), listeners(List

4、从Classpath推断Web应用类型,调用的是WebApplicationType类的deduceFromClasspath()方法。如果Classpath中包含DispatcherHandler,则表明当前WebApplicationType为REACTIVE;如果既不包含javax.servlet.Servlet也不包含Spring中的ConfigurableWebApplicationContext,则表明当前WebApplicationType为NONE; 上述两种都不是则表明当前WebApplicationType是SERVLET

static WebApplicationType deduceFromClasspath() {
        // 如果org.springframework.web.reactive.DispatcherHandler的class文件存在且可以加载
        //不存在org.springframework.web.servlet.DispatcherServlet
        //不存在org.glassfish.jersey.servlet.ServletContainer
        //则返回REACTIVE表明 该应用程序应作为响应式Web应用程序运行,并应启动嵌入式servlet Web 服务器
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        //遍历SERVLET 指标类
        //如果不存在javax.servlet.Servlet也不存在org.springframework.web.context.ConfigurableWebApplicationContext
        //则返回NONE表明该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        //返回SERVLET表明该应用程序应作为基于servlet的 Web 应用程序运行,并应启动嵌入式 servlet Web 服务器。
        return WebApplicationType.SERVLET;
    }

spring.factories的加载时机
1、在构建SpringApplication中,初始化其属性bootstrapRegistryInitializers属性时进行加载 /META-INF/spring.factories。
2、构建SpringApplication对象时,通过调用getSpringFactoriesInstances(Class type)获取工厂实例。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        ......
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrapRegistryInitializers = new ArrayList<>(
                getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        ......
    }

3、我们以初始化bootstrapRegistryInitializers为例讲解,getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object… args)中首先获取ClassLoader ,通过SpringFactoriesLoader机制,根据ClassLoader从类路径jar包中加载META-INF/spring.factories下的所有工厂类及其实现类 。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        //获取ClassLoader 
        ClassLoader classLoader = getClassLoader();
        // 使用SpringFactoriesLoader机制加载出工厂名,并放入Set集合中确保其唯一性。但是在META-INF/spring.factories中并无BootstrapRegistryInitializer所以此处的names的size为0。
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //创建Spring工厂实例(但因为上述names的size为0,所以对于BootstrapRegistryInitializer来说它并不会创建SpringFactory实例)
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        //通过AnnotationAwareOrderComparator对Spring工厂实例排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

4、SpringFactoriesLoader中的loadFactoryNames来加载META-INF/spring.factories下的所有工厂类及其实现类

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        //获取当前使用的ClassLoader
        ClassLoader classLoaderToUse = classLoader;
        if (classLoaderToUse == null) {
            //为空,则获取SpringFactoriesLoader的类加载器
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
        //org.springframework.boot.BootstrapRegistryInitializer
        String factoryTypeName = factoryType.getName();
        //加载META-INF/spring.factories下的扩展类,没有值的返回一个空列表。
        return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

5、重点关注SpringFactoriesLoader中的loadSpringFactories(ClassLoader classLoader),该方法具体实现了从META-INF/spring.factories下加载扩展类。

//工厂类所在位置,在多个jar文件中都有。
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        //检查缓存中是否有工厂类
        Map<String, List<String>> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }
        //缓存中没有,初始化result
        result = new HashMap<>();
        try {
            //加载META-INF/spring.factories下的一系列元素
            Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
            //迭代遍历
            while (urls.hasMoreElements()) {
                //spring-boot-版本号.jar文件中Spring.factories所在的绝对路径
                URL url = urls.nextElement();
                //构建UrlResource
                UrlResource resource = new UrlResource(url);
                //加载该UrlResource中的属性(即Spring.factories中的键值对)
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    //父类工厂类型名
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    //子类工厂实现类名数组(在Spring.factories中多个用逗号分隔)
                    String[] factoryImplementationNames =
                            StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                    //将工厂类型名,工厂实现类列表放入名为result的 Map<String, List<String>>中,key为工厂类型名,value为工厂实现类列表。
                    for (String factoryImplementationName : factoryImplementationNames) {
                        result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                                .add(factoryImplementationName.trim());
                    }
                }
            }

            //将result中的所有list都置为包含唯一元素的不可修改的list
            result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
                    .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
            //放入缓存。        
            cache.put(classLoader, result);
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
        return result;
    }
bootstrapRegistryInitializers 的初始化中实现了加载META-INF/spring.factories中工厂扩展类(但是在META-INF/spring.factories并无bootstrapRegistryInitializers ),并将其放入缓存Map<String, List>,其中key为父类工厂名,value为其对应扩展类列表。之后initializers(ApplicationContextInitializer列表)以及listeners(ApplicationListener列表)的初始化都是从该缓存中获取值。

6、接下里我们看一下第三步中的createSpringFactoriesInstances()方法。由于bootstrapRegistryInitializers 在META-INF/spring.factories中并不存在。所以我们只有它返回的instances是空的即它不会创建SpringFactoriesInstances。但是初始化initializers,listeners时,却会。我们看一下具体源码。

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
            ClassLoader classLoader, Object[] args, Set<String> names) {
        //初始化names.size()大小的list存放创建出来的实例。
        List<T> instances = new ArrayList<>(names.size());
        //遍历传入的工厂扩展类实例名
        for (String name : names) {
            try {
                //通过反射获取instance的Class对象
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                //instanceClass是一个type类型,向下,否则抛异常IllegalArgumentException
                Assert.isAssignable(type, instanceClass);
                //获取instanceClass的构造器
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                //通过BeanUtils的instantiateClass()方法实例化类。
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                //将实例化出来的类放入instances
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }
标签: springboot

本文转载自: https://blog.csdn.net/cliper9768/article/details/132009114
版权归原作者 null如也 所有, 如有侵权,请联系我们删除。

“SpringApplication对象的构建及spring.factories的加载时机”的评论:

还没有评论