springboot源码学习2 自动装配原理学习

一 构建基础项目

  1 构建依赖:   

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cxy</groupId>
    <artifactId>register-sever</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>register-sever</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

  2 查看启动类:  

@SpringBootApplication
//@Import({ImportTest.class, SelfImportSelector.class, SelfImportBeanDefinitionRegistrar.class})
public class RegisterSeverApplication {

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

}

  3 编写测试接口:

 先忽略注释的代码 

@RestController
public class Rest {
/*    @Autowired
    ImportTest importTest;
    @Autowired
    ImportTestC importTestC;
    @Autowired
    ImportTestD importTestD;*/
    @RequestMapping("/hello")
    public String get(){
       // importTest.test();
       // importTestC.test();
      //  importTestD.test();
        return "hello";
    }
}

  4 启动main方法

  调用http://localhost:8080/hello  获取结果为hello  就可以了  很多在想直接源码上不就好了么,其实可以看到代码中有很多注释的东西,这个就是为啥要这么做的原因,下面会继续讲

二  源码跟踪

  1构造方法

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // resourceLoader == null
        this.resourceLoader = resourceLoader;

        Assert.notNull(primarySources, "PrimarySources must not be null");
        //primarySources 为基础类
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 设置初始化器
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 设置监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

   2 入口

 所有的方法入口都是main方法所以我们可以跟进main方法进去:

    public ConfigurableApplicationContext run(String... args) {
        // 创建计时器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // 设置handlerless为true
        configureHeadlessProperty();
        // 获取监听器 启动
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 预处理环境信息
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            // 设置configureIgnoreBeanInfo 为true
            configureIgnoreBeanInfo(environment);
            // 打印banner
            Banner printedBanner = printBanner(environment);
            // 创建上下文ConfigurableApplicationContext
            context = createApplicationContext();
            // 获取异常报信息
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            // 预处理context
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // 刷新context  调用spring得refresh方法
            refreshContext(context);
            // 空实现
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            // 启动监听器
            listeners.started(context);
            // 执行命令行操作
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            // 异常处理,打印异常报告
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            // 启动监听器
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

 

  3 getRunListeners(args)方法

是获取 META-INF/spring.factories中配置的内容核心方法,配置的监听器  内容如下
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        // 获取类加载器
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        // 通过传入参数的class类型,来获取具体内容的集合  获取listener时候  传入 SpringApplicationRunListener
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 创建实例
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

  4 prepareEnvironment(listeners, applicationArguments)方法

    这个方法是进行环境的预处理,就是激活相关配置文件,例如**.yml  核心方法 configureEnvironment


protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
// 处理配置文件
configurePropertySources(environment, args);
// 激活
configureProfiles(environment, args);
}

  5 createApplicationContext方法

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        //根据类型进行判断加载哪个ConfigurableApplicationContext
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    // servlet
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                    // REACTIVE
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    // 普通main方法
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

  6  getSpringFactoriesInstances方法处理实例

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        // 获取类加载器
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        // 通过传入参数的class类型,来获取具体内容的集合  获取listener时候  传入 SpringApplicationRunListener
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 创建实例
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

  7 prepareContext预处理方法

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        // 对容器得一个后处理 beanNameGenerator resourceLoader ConversionService
        postProcessApplicationContext(context);
        // 执行初始化器
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            // 打印profile信息
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        //获取beanfactory  后续到beanfactory进行必要设置
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        // 封装参数注册到获取beanfactory
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //如果beanfactory存在  注册单例bean
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            // 设置bean对象是否可以重载
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.lazyInitialization) {
            // 懒加载
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        // 找到所有得配置源
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 进入load方法
        load(context, sources.toArray(new Object[0]));
        // 触发contextLoaded的完成
        listeners.contextLoaded(context);
    }

  8 refreshContext

这个方法是最复杂的方法,会加载AutoConfigurationImportSelector内容 会调用spring的refresh方法  最终解析配置文件的方法在processImports方法中

    for (SourceClass candidate : importCandidates) {
                    if (candidate.isAssignable(ImportSelector.class)) {
                        // Candidate class is an ImportSelector -> delegate to it to determine imports
                        Class<?> candidateClass = candidate.loadClass();
                        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                this.environment, this.resourceLoader, this.registry);
                        Predicate<String> selectorFilter = selector.getExclusionFilter();
                        if (selectorFilter != null) {
                            exclusionFilter = exclusionFilter.or(selectorFilter);
                        }
               // 这一步是加载自动配置的关键 获取元数据加载
if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } }
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered 

可以看到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中核心方法:

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }

实现了这个方法就会被加载到springboot

  9 handleRunFailure 异常处理方法

    private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
            Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
        try {
            try {
                // 处理退出code
                handleExitCode(context, exception);
                if (listeners != null) {
                    listeners.failed(context, exception);
                }
            }
            finally {
                // 报告异常
                reportFailure(exceptionReporters, exception);
                if (context != null) {
                    context.close();
                }
            }
        }
        catch (Exception ex) {
            logger.warn("Unable to close ApplicationContext", ex);
        }
        // 通过反射  报告具体类型
        ReflectionUtils.rethrowRuntimeException(exception);
    }

三 测试

  1 新建三个类:

public class ImportTest {
    public void test(){
        System.out.println("我是中国人");
    }

}
public class ImportTestC {
    public void test(){
        System.out.println("测试testc");
    }
}
public class ImportTestD {
    public void test(){
        System.out.println("测试testD");
    }
}
public class SelfImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.cxy.registersever.study.ImportTestC"};
    }
}
public class SelfImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition root = new RootBeanDefinition(ImportTestD.class);
        registry.registerBeanDefinition("importTestD", root);
    }
}

 

2 引入:

@SpringBootApplication
@Import({ImportTest.class, SelfImportSelector.class, SelfImportBeanDefinitionRegistrar.class})
public class RegisterSeverApplication {

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

}

3 测试:

@RestController
public class Rest {
    @Autowired
    ImportTest importTest;
    @Autowired
    ImportTestC importTestC;
    @Autowired
    ImportTestD importTestD;
    @RequestMapping("/hello")
    public String get(){
        importTest.test();
        importTestC.test();
        importTestD.test();
        return "hello";
    }
}

idea可能会报importTestC ,importTestD找不到,但是不影响,执行方法控制台会打印相关内容



  



 



 

posted @ 2021-10-15 10:47  菩提树下的韦小宝  阅读(49)  评论(0编辑  收藏  举报