前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入Spring Boot自动装配

深入Spring Boot自动装配

作者头像
星哥玩云
发布2022-09-15 14:01:13
2950
发布2022-09-15 14:01:13
举报
文章被收录于专栏:开源部署开源部署

1、Spring Boot自动装配原理

依赖@Enable模块驱动设计模式,@EnableAutoConfiguration必然会“@Import” ImportSelector或ImportBeanDefinitionRegister的实现类,查看源码:

代码语言:javascript
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ......
}

其中AutoConfigurationImportSelector就是@EnableAutoConfiguration 所需"@Import"的DeferredImportSelector实现类,由于DeferredImportSelector作为ImportSeldector的子接口,所以组件自动装配逻辑均在selectImports方法中.

源码:

代码语言:javascript
复制
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    ......
    @Override
  //根据autoConfigurationMetadata条件执行过滤    
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
    //加载自动装配的元信息
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		//获取自动装配的类名集合
      AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
  }
	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
    //获取@EnableAutoConfiguration标注类的元信息
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//获取自动装配的候选类名集合
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    //移除重复对象
		configurations = removeDuplicates(configurations);
    //获取自动装配排除名单
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
    //根据autoConfigurationMetadata条件执行过滤
		configurations = filter(configurations, autoConfigurationMetadata);
		//自动装配的导入事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

解析:

  • AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader);加载自动装配的元信息
  • AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);获取自动装配信息
  • AnnotationAttributes attributes = getAttributes(annotationMetadata);获取@EnableAutoConfiguration标注类的元信息
  • List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取自动装配的候选类名集合
  • configurations = removeDuplicates(configurations);移除重复对象
  • Set exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions);获取自动装配黑名单
  • configurations = filter(configurations, autoConfigurationMetadata);根据autoConfigurationMetadata条件执行过滤
  • fireAutoConfigurationImportEvents(configurations, exclusions);自动装配的导入事件

1.1、@EnableAutoConfiguration读取侯选装配组件

源码:

代码语言:javascript
复制
	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;
	}
  //获取Spring Factories加载工厂类
	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}
  //通过名字讲行加载
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
  //装载Spring Factories工厂机制
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        //从缓存中获取
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
               //搜索指定Classpath下所有的META-INF/spring.factories资源内容
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
								//循环遍历spring.factories资源内容
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    //将资源内容制作为properties文件
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
										//合并为一个key为接口全类名,value是实现类全类名列表
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        //接口全类名
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;
												
                        for(int var11 = 0; var11 < var10; ++var11) {
                          //实现类全类名  
                          String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }
								//放入缓存
                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

1.2、@EnableAutoConfiguration排除自动装配组件

源码:

代码语言:javascript
复制
	//获取要排除的自动装配组件
  protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //用于存储排除名单
		Set<String> excluded = new LinkedHashSet<>();
    
    //添加排除类,spring.autoconfigure.exclude
		excluded.addAll(asList(attributes, "exclude"));
		//添加排除类名,spring.autoconfigure.excludeName            excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    //添加所有的自动装配排除集合,用于后面检查类名集合是否合法
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}

1.3、@EnableAutoConfiguration过滤自动装配组件

源码:

代码语言:javascript
复制
	 //获取要过滤的自动装配组件
   private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
    //将自动装配类名转化为字符串数组
		String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
		boolean skipped = false;
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			invokeAwareMethods(filter);
      //查检是否匹配
			boolean[] match = filter.match(candidates, autoConfigurationMetadata);
			for (int i = 0; i < match.length; i++) {
				//如果需要过滤
        if (!match[i]) {
					skip[i] = true;
					candidates[i] = null;
					skipped = true;
				}
			}
		}
    //如果不需要过滤,直接返回
		if (!skipped) {
			return configurations;
		}
		List<String> result = new ArrayList<>(candidates.length);
		//如果需要过滤,将过滤后的对象放入result
    for (int i = 0; i < candidates.length; i++) {
			if (!skip[i]) {
				result.add(candidates[i]);
			}
		}
		if (logger.isTraceEnabled()) {
			int numberFiltered = configurations.size() - result.size();
			logger.trace("Filtered " + numberFiltered + " auto configuration class in "
					+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
		}
    //返回过滤后的类名集合
		return new ArrayList<>(result);
	}
  //获取由所有ImportFilters集合
	protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

2、 自定义Spring Boot Starter

2.1、 新添加Maven工程

pom.xml文件如下:

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tyschool</groupId>
    <artifactId>formatter-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.2.6.RELEASE</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2.2、 新建格式化接口

代码语言:javascript
复制
public interface Formatter {
    
    String format(Object obj);
}

2.3、 实现接口

代码语言:javascript
复制
public class DefaultFormatter implements Formatter {
    
    public String format(Object obj) {
        return String.valueOf(obj);
    }
}

2.4、 实现DefaultFormatter自动装配

代码语言:javascript
复制
@Configuration
public class FormatterAutoConfiguration {
    
    @Bean
    public Formatter defaultFormatter(){
        return new DefaultFormatter();
    }
}

2.5、 在META-INF/spring.factories资源声明FormatterAutoConfiguration

代码语言:javascript
复制
# FormatterAutoConfiguration 自动装配声明
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tyschool.autoconfigure.config.FormatterAutoConfiguration

2.6、 构建Spring Boot Starter

代码语言:javascript
复制
 mvn -Dmaven.test.skip -U clean install

2.7、 添加formatter-spring-boot-starter依赖

代码语言:javascript
复制
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.2.6.RELEASE</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.tyschool</groupId>
            <artifactId>formatter-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

2.8、 新建引导类

代码语言:javascript
复制
@SpringBootApplication
public class FormatterBootStrap {

    public static void main(String[] args) {
        //创建Spring 上下文
        ConfigurableApplicationContext context = new SpringApplicationBuilder(FormatterBootStrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name","tyschool");
        //获取bean
        Formatter formatter = context.getBean(Formatter.class);
        //格式化数据并输出
        System.out.println(formatter.format(map));
        context.close();
    }
}
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Spring Boot自动装配原理
    • 1.1、@EnableAutoConfiguration读取侯选装配组件
      • 1.2、@EnableAutoConfiguration排除自动装配组件
        • 1.3、@EnableAutoConfiguration过滤自动装配组件
        • 2、 自定义Spring Boot Starter
          • 2.1、 新添加Maven工程
            • 2.2、 新建格式化接口
              • 2.3、 实现接口
                • 2.4、 实现DefaultFormatter自动装配
                  • 2.5、 在META-INF/spring.factories资源声明FormatterAutoConfiguration
                    • 2.6、 构建Spring Boot Starter
                      • 2.7、 添加formatter-spring-boot-starter依赖
                        • 2.8、 新建引导类
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                        http://www.vxiaotou.com