装配 SpringBoot自动配置流程( 三 )

  1. getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes);
    /** *根据注解元数据和注解的属性信息 获取应该进行自动配置的类名,可以理解为自动配置的候选项(初选名单) *param1 元注解数据 *param2 元注解数据的属性信息集合 *return List<String> 存储的数据就是应该继续宁自动配置的类名*/protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {/*** SpringFactoriesLoader是一个用于框架内部使用的通用工厂加载机制***/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;}
对自动配置项进行去重处理
  1. 1 configurations = removeDuplicates(configurations);对自动配置的类名进行去重处理
//通过removeDuplicates()方法对自动配置的类名进行去重处理//利用Set集合数据不重复特性,将list集合存储到LinkedHashSet集合中进行去重处理,而后再将去重的结果存储到List集合中返回protected final <T> List<T> removeDuplicates(List<T> list) {return new ArrayList<>(new LinkedHashSet<>(list));}从自动配置项中筛选被排除配置项
  1. configurations.removeAll(exclusions);
//从自动配置候选项中筛选需排除配置项protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {//创建一个需排除配置项集合excludedSet<String> excluded = new LinkedHashSet<>();//从属性信息集合中获取到key为exclude的值,将其存储到excluded集合中excluded.addAll(asList(attributes, "exclude"));//从属性信息集合中获取到key为excludeName的数据,返回的是一个字符串数组,返回后将其转化为List集合,存储到excluded集合中excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));/*** getExcludeAutoConfigurationsProperty():*返回 spring.autoconfigure.exclude 属性排除的自动配置*/excluded.addAll(getExcludeAutoConfigurationsProperty());return excluded;}-----------------------------------------------------------------------------------------/*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/-----------------------------------------------------------------------------------------//attributes.getStringArray("excludeName")public String[] getStringArray(String attributeName) {return getRequiredAttribute(attributeName, String[].class);}exclude 和excludeName 都是指定某些类在项目启动时不进行自动配置,其一般在@SpringBootApplication 中进行配置 。
检查是否有无效的排除类存在
  1. 1 configurations.removeAll(exclusions);
//检查是否有无效的排除类存在private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) { //创建一个用于存储无效配置项的集合List<String> invalidExcludes = new ArrayList<>(exclusions.size()); //循环需排除配置项for (String exclusion : exclusions) {//根据类的全限定名判断该类是否存在且可以被加载,并且 需排除配置项集合是否包含该类if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {//如果存在,且不再需排除配置项的集合中,将其添加到无效配置项集合中invalidExcludes.add(exclusion);}}//如果无效配置项集合不为空,说明存在无效配置项if (!invalidExcludes.isEmpty()) {//处理无效配置项 --> 报错 IllegalStateException 无效状态异常handleInvalidExcludes(invalidExcludes);}}-----------------------------------------------------------------------------------------/*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/-----------------------------------------------------------------------------------------/** *ClassUtils.isPresent() 根据类名称判断是否存在并且可以加载,如果类或其依赖项之一不存在或无法加载返回false * param1 className 要检查的类的名称 * param2 classLoader 要使用的类加载器(如果为null,表示默认的类加载器) */public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {try {//forName(类名称,类加载器) 用于替换Class.forName()方法,并且还返回所提供名称的类实例forName(className, classLoader);return true;}catch (IllegalAccessError err) {throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +className + "]: " + err.getMessage(), err);}catch (Throwable ex) {// Typically ClassNotFoundException or NoClassDefFoundError...return false;}}

经验总结扩展阅读