Spring boot自动装载(源码解析)

过几天公司培训,我这边整理了下PPT。顺便写了点代码,我放GitHub上了

 

Springboot 的基本认识

     对于 spring 框架,我们接触得比较多的应该是 spring mvc、 和 spring。而 spring 的核心在于 IOC(控制反转)和 DI (依赖注入)。而这些框架在使用的过程中会需要配置大量 的 xml,或者需要做很多繁琐的配置。 springboot 框架是为了能够帮助使用 spring 框架的开发 者快速高效的构建一个基于 spirng 框架以及 spring 生态 体系的应用解决方案。它是对“约定优于配置”这个理念下 的一个最佳实践。因此它是一个服务于框架的框架,服务 的范围是简化配置文件。

约定优于配置的体现

约定优于配置的体现主要是

1. maven 的目录结构  

  a) 默认有 resources 文件夹存放配置文件  

  b) 默认打包方式为 jar

2. spring-boot-starter-web 中默认包含 spring mvc 相关 依赖以及     内置的 tomcat 容器,使得构建一个 web 应用 更加简单

3. 默认提供 application.properties/yml 文件

4. 默认通过 spring.profiles.active 属性来决定运行环境时 读取的配置文件

5. EnableAutoConfiguration 默认对于依赖的 starter 进行 自动装载

Springboot 启动的核心注解

1. @Configuration

现在目前应该是大多数互联网的主要配置方式,如果知道或者用过就可以不看下面的文字了。它是 JavaConfig 形式的基于 Spring IOC 容器的配置类使用的一种注解 ,因为SpringBoot 本质上就是一个 spring 应用,所以通过这个注解来加载 IOC 容器的配置是很正常的。所以在启动类 里面标注了@Configuration,意味着它其实也是一个 IoC 容器的配置类。传统意义上的 spring 应用都是基于 xml 形式来配置 bean 的依赖关系。然后通过 spring 容器在启动的时候,把 bean 进行初始化并且,如果 bean 之间存在依赖关系,则分析这 些已经在 IoC 容器中的 bean 根据依赖关系进行组装。 直到 Java5 中,引入了 Annotations 这个特性,Spring 框 架也紧随大流并且推出了基于 Java 代码和 Annotation 元 信息的依赖关系绑定描述的方式。也就是 JavaConfig。 从 spring3 开始,spring 就支持了两种 bean 的配置方式, 一种是基于 xml 文件方式、另一种就是 JavaConfig 任何一个标注了@Configuration 的 Java 类定义都是一个 JavaConfig 配置类。而在这个配置类中,任何标注了 @Bean 的方法,它的返回值都会作为 Bean 定义注册到 Spring 的 IOC 容器,方法名默认成为这个 bean 的 id

2. @EnableAutoConfiguration

Enable 主机应该是在 JavaConfig 框架上更进一 步的完善,是的用户在使用 spring 相关的框架是,避免配 置大量的代码从而降低使用的难度 比如常见的一些 Enable 注解:EnableWebMvc,(这个注 解引入了 MVC 框架在 Spring 应用中需要用到的所有 bean); 比如说@EnableScheduling,开启计划任务的支持; 找到 EnableAutoConfiguration,我们可以看到每一个涉及 到 Enable 开头的注解,都会带有一个@Import 的注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	xxxx

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
    xxxx
}

 

EnableAutoConfiguration中也是个复合注解 包含

AutoConfigurationPackage。Import注解

Spring boot自动装载(源码解析)_第1张图片2.1 @Import

import 注解是什么意思呢? 联想到 xml 形式下有一个 形式的注解,就明白它的作用了。 import 就是把多个分来的容器配置合并在一个配置中。在 JavaConfig 中所表达的意义是一样的。见代码。

1. 第一种就是前面演示过的,基于普通 bean 或者带有 @Configuration 的 bean 进行诸如

2. 实现 ImportSelector 接口进行动态注入

3. 实现 ImportBeanDefinitionRegistrar 接口进行动态注入

 

2.1.1通过import注入其他配置类加载其他包下面的bean

@Import(OtherConfig.class)
@Configuration
public class SpringConfig {

    @Bean
    public DefaultBean defaultBean(){
        return new DefaultBean();
    }
}
@Configuration
public class OtherConfig {

    //iff ...
    //else ..
    @Bean
    public OtherBean otherBean(){
        return new OtherBean();
    }
}

2.1.2  import注入 xxxxImportSelector

我们来着这个类,是实现了 ImportSelector,也就是说所有实现类 ImportSelector接口的实现类,可以作为import注解的参数

AutoConfigurationImportSelector implements DeferredImportSelector 》DeferredImportSelector extends ImportSelector

public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

}

让我们来看下接口实现

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
        //加载文件"META-INF/" + "spring-autoconfigure-metadata.properties"
        //返回包装类,里面其实是kv
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
         //返回SPI加载的bean实体。List beanNames
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
        //返回数组后,就会托管到SPRIng容器中,具体可以看上面那个博客
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

//返回SPI加载的bean实体。List beanNames
	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
        //返回EnableAutoConfiguration.class.name作为key
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //SpringFactoriesLoader.loadFactoryNames传入 key,SpringFactoriesLoader查找说有classpath下的META-INF/spring.factories返回对应的全路径名称
		List configurations = getCandidateConfigurations(annotationMetadata, attributes);
        //去重
		configurations = removeDuplicates(configurations);
        //获取排除的类
		Set exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
        //过滤条件注解比如OnBeanCondition这种进行条件判断
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

这里面会加载对应的配置

Spring boot自动装载(源码解析)_第2张图片

2.1.3 ImportBeanDefinitionRegistrar 接口进行动态注入

3. @ComponentScan

ComponentScan 这个注解是大家接触得最多的了,相当 于 xml 配置文件中的。 它的主要作用就是扫描指定路径下的标识了需要装配的类,自 动装配到 spring 的 Ioc 容器中。 标识需要装配的类的形式主要是:@Component、 @Repository、@Service、@Controller 这类的注解标识的 类。 ComponentScan 默认会扫描当前 package 下的的所有加 了相关注解标识的类到 IoC 容器中;

 

 

我们可以直接用这三个注解也可以启动 springboot 应用, 只是每次配置三个注解比较繁琐,所以直接用一个复合注 解更方便些。 然后仔细观察者三个注解,除了 EnableAutoConfiguration 可能稍微陌生一点,其他两个注解使用得都很多

你可能感兴趣的:(spring,SpringBoot)