• springboot源码(二)


    springboot自动装配原理分析

    1. 何为自动装配?

         基于springboot源码(一)的内容后,spring一直都在致力于解决一个问题,就是如何让bean的管理变得更简单,让开发者尽可能的少关注一些基础化bean的配置,多关注业务代码。所以实现自动装配。

              自动装配就是如何自动将bean装载到IOC容器中。

              实际上,在Enablexxxx模块驱动的出现已经有了自动装配的雏形,真正能够实现这一机制,还是spring4.0版本中的@Conditional注解的出现。

              接下来就聊一下自动装配到底是个什么玩应儿......

             2.自动装配的演示(以Redis为类)

             添加依赖:     

    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency> 

             添加配置:

    spring:
        redis:
          host: 127.0.0.1 
          port: 6379

              使用:

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

               按照上面的顺序添加,就可以使用redisTemplate了。所以就会想redisTemplate为什么可以被直接注入?什么时候注入的?

                这就是自动装配,可以把classpath下依赖包的相关的bean,自动装载到Spring IOC 容器中。怎么做到的呢??????

    来吧上源码

              3.自动装配源码分析

    @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
    
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
    Class<?>[] exclude() default {};

    /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
    String[] excludeName() default {};

    }

    引入了一个AutoConfigurationImportSelector.class   根据上一篇内容会联想到@import注解,实现ImportSelector的方式   可以把需要纳入IOC管理的bean放到一个String[]中。

    看一下AutoConfigurationImportSelector这个类

     实现了ImportSelector这个接口,来看一下selectImports()方法

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    //把autoConfigurationEntry.getConfigurations()转换成一个String[],虽然现在还不知道返回的内容是什么
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
    //搞清楚autoConfigurationEntry是什么。
    protected
    AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //从META-INF/spring.factories中获取EnableAutoConfiguration类型的全类路径名 List
    <String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions);
    //从META-INF/spring-autoconfigure-metadata.properties中找到自动装载的条件,类似于@Conditional注解的作用 configurations
    = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //getSpringFactoriesLoaderFactoryClass()-->EnableAutoConfiguration.class 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; }
    
    
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    String factoryTypeName = factoryType.getName();
    //只获得key为EnableAutoConfiguration的
    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader);
    //只加载一次
    if (result != null) { return result; } try {
    //从META-INF/spring.factories下获取所有的url 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); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

    得到EnableAutoConfiguration的已经知道,接下来看过滤

    private ConfigurationClassFilter getConfigurationClassFilter() {
            if (this.configurationClassFilter == null) {
    //从META-INF/spring.factories中得到key为AutoConfigurationImportFilter的 List
    <AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters(); for (AutoConfigurationImportFilter filter : filters) { invokeAwareMethods(filter); }
    //从META-INF/spring-autoconfigure-metadata.properties中获取自动装载的条件xxxx.conditionalOnBean、conditionalOnClass等
    this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters); } return this.configurationClassFilter; }

    接下来就是filter()方法,根据configurations  、autoConfigurationMetadata 根据过滤器的条件进行过滤就ok了。

    到这springboot的自动装配机制的主要流程就大致说完了。

  • 相关阅读:
    Ubuntu搭建flask服务器, 部署sklearn 机器学习模型
    Jupyter-notebook 显示图片的两种方法
    Linux多版本opencv指定 & CMake中 find_package()的原理解析
    使用C++调用pytorch模型(Linux)
    Arch / Manjaro Linux下 Opencv 编译 配置 查看
    获取路径下所有特定格式文件列表
    Pycharm相对路径
    opencv 与操作 bitwise_and
    vim学习
    opencv 旋转 点旋转 以及 逆旋转
  • 原文地址:https://www.cnblogs.com/bentuzi/p/16057313.html
Copyright © 2020-2023  润新知