Sping Boot 学习-进阶

Posted 菜鸟-肥龙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sping Boot 学习-进阶相关的知识,希望对你有一定的参考价值。

一、Spring Boot 自动装配原理

1.1、核心注解解析

1、@SpringBootApplication

  • @SpringBootApplication 是 SpringBoot 启动类上的注解,标志着该类是一个启动类。
  • @SpringBootApplication 是一个复合注解,其中主要包括 @SpringBootConfiguration、SpringBootConfiguration、SpringBootConfiguration
  • 注解关系如下图:

2、@SpringBootConfiguration

  • 是一个自定义注解,点进去之后可以看见其是由 元注解 + @Configuration 组成。
  • @Configuration 表明该类是一个配置类。
  • @Configuration 注解点进去可以看见 @Component 注解,说明其被 Spring IOC 容器所管理。

3、@EnableAutoConfiguration

  • 见名知意,@EnableAutoConfiguration 是自动装配的核心注解。
  • @EnableAutoConfiguration 是一个复合注解,其组成注解包括 @AutoConfigurationPackage、@Import(AutoConfigurationImportSelector.class)

4、@AutoConfigurationPackage

  • @AutoConfigurationPackage 也是一个复合注解,其由 元注解 + @Import(AutoConfigurationPackages.Registrar.class) 注解组成。
  • 这个注解是自动配置包,主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是AutoConfigurationPackages.Registrar.class 类。
  • 就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。

5、@ComponentScan

  • 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilterAutoConfigurationExcludeFilter
@ComponentScan(excludeFilters =  @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) )

1.2、核心类解析

1、AutoConfigurationPackages.Registrar.class

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) 

	register(registry, new PackageImport(metadata).getPackageName());

  • metadata :主配置类的全路径类名。
  • debug 可以看见 ‘’new PackageImport(metadata).getPackageName()‘’,获得是主配置所在包下的包名。

2、AutoConfigurationImportSelector.class

  • AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中
@Override
	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;
		
		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);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	

=====================================================================================
    
    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;
	

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) 
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) 
			return result;
		

		try 
			Enumeration<URL> urls = (classLoader != null ?
				\'classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					\'ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));\'
			result = new LinkedMultiValueMap<>();
  • Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。
`AutoConfigure/META-INF/spring.factories: 里面包含了所有springBoot整合的类的全路径类名,基于反射射原理通过类加载器就能获取类的实例对象 .  ”\\ “是换行使用的

`AutoConfigure/META-INF/spring-configation-metadata.json: 里面配置所有springBoot整合的类的相关默认配置.

1.3、@Condition

# EnableAutoConfiguration 能获得所有的SpringBoot整合的类的实例化对象,但并不是每个类它都会将创建并注入SpringIOC容器之中,只有引入了相关的依赖,其才会将类创建对象.@Condition是实现这一个功能的注解.	
 	
 	Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载相应的Bean
@Conditional要配合Condition的实现类(ClassCondition)进行使用.

`在AutoConfigure/org.springframework.boot.autconfigure/comdition 文件下springboot提供了大量的条件注解,其中常用的有:
ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

1.4、@Import

# @Enable*底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:
①导入Bean
②导入配置类
③导入 ImportSelector 实现类。一般用于加载配置文件中的类
④导入 ImportBeanDefinitionRegistrar 实现类。
- 导入Bean  @Import(User.class)
- 导入配置类  @Import(UserConfig.class)

二、Spring Boot 零配置原理

2.1、Spring Boot 零配置原理分析

	SpringBoot框架主要的特性就是简化Spring开发的过程,它只是整合了Sprin并没有对其做什么其他的改动。Spring在开发过程中就提供配置文件(Application.xml)或纯注解开发两种模式,在纯注解开发的过程中就已经不需要配置任何的配置文件了。在配置文件模式下开发,就需要提供 \'SpringApplication.xml\' \'SpringMVCApplication.xml\' \'Web.xml\'等三个比较主要的配置文件。
	\'SpringApplication.xml\'  & \'SpringMVCApplication.xml\'配置文件可以通过创建相应的配置类来替代掉,在对应的配置中添加 \'@Configuration\' + \'@Bean\'注解。
	Spring的IOC容器和SpringMVC中的IOC容器具有父子容器的概念,SpringMVC的IOC容器为子容器,Spring的IOC容器为父容器,子容器中的Bean能调用父容器中的方法,父容器中的方法不能调用子容器中的Bean.
	当启动一个\'WEB\'项目时,容器(Tomcat)首先会读取项目\'web.xml\'配置文件里的配置。所以要替换掉\'web.xml\'文件就得在项目启动之初就能被加载到。这里就涉及到一个\'SPI\'机制的概念。
	\'SPI\'是Servlet3.0之后推出的一种规范,是JDK内置的一种服务发现机制,Java提供的一套被第三方实现或扩展的API。它规定在jar包的\'META-INFO/services\'目录下创建以\'服务接口全路径类名命名的文件\',该文件里是该接口的具体\'实现类的全路径类名\'。当外部的程序(Tomcat)装配这个模块时,就能通过\'(SpringMVC)jar/META-INFO/services/\'里的配置文件找到具体的实现类的全路径类名,然后通过反射机制获取对应类的实例化对象。
    找到对应的SpringMVV的jar包,找到META-INFO/services/。该目录下就有一个SevletContainerInitializer接口的全路径类名为文件名的文件,文件内容就是该接口的具体实现类-SpringServletContainerInitalizer。
    \'SpringServletContainerInitalizer\':在这个类的上方定义了一个\'@HandlesTypes\'注解,该注解中配置类\'WebApplicationInitializer.class\'。它会将\'WebApplicationInitializer\'所有的实现类添加到\'onStartup()\'方法的\'Set<Class<?>>\'集合之中(\'ServletContainerInitializer\'接口中只有\'onStartup()\'一个方法).
	SpringServletContainerInitializer类中会将所有\'WebApplicationInitializer\'接口的实现类实例化,然后循环执行\'onStartup(servletContext)\'方法.

2.2、SPI 机制

# 1.什么是SPI机制
	SPI(service provider Interface) ,是JDK内置的一种服务发现机制,是java提供的一套被第三方实现或扩展的API.它规定在\'org.springframework:spring-web.jar\'包的\'META-INFO/services\'目录下创建一个以\'服务接口全路径类名命名的文件\',该文件里是该接口的具体\'实现类的全路径类名\'.当外部程序(Tomcat)装配这个模块是,就能通过\'jar/META-INFO/services/\'里的配置文件找到具体的实现类的全路径类名,通过反射机制完成实例化.
\'org.springframework.web.SpringServletContainerInitializer\'
# 2.为什么一定要在 classes 中的 	META-INFO/services 下呢?
	JDK提供服务实现查找的一个工具类: java.util.ServiceLoader 在这个类里面写死了
	//默认会去这里寻找相关信息
	private static final String PREFIX = \'META-INFO/services\';

2.3、SpringServletContainerInitializer 分析

 1.SpringServletContainerInitializer类的作用
	\'@HandlesTypes\'注解中配置\'WebApplicationInitializer.class\',它会将\'WebApplicationInitializer\'所有的实现类添加到\'onStartup()\'方法的\'Set<Class<?>>\'集合之中(\'ServletContainerInitializer\'接口中只有\'onStartup()\'一个方法).
	SpringServletContainerInitializer类中会将所有\'WebApplicationInitializer\'接口的实现类实例化,然后循环执行\'onStartup(servletContext)\'方法.

三、内置Tomcat原理解析

SpringBoot 在启动的时候会加载到\'TomcatWebServer\' 类对象,执行里面的初始化方法,初始方法中会调用一个\'tomcat.start()\',将内置tomcat进行启动.
	Apache提供了一款内嵌式的Tomcat,引入相关依赖让项目可以以 jar 的形式发布, 其中有一个\'Tomcat\'的类,可以创建器对象,\'tomcat.start()\',能启动整个tomcat项目.

以上是关于Sping Boot 学习-进阶的主要内容,如果未能解决你的问题,请参考以下文章

D15 Sping Boot 入门 Sping框架--Java Web之书城项目 购物车模块

D08 Sping Boot 入门 Sping框架--Java Web之JSP

D16 Sping Boot 入门 Sping框架--Java Web之书城项目 dingda模块

D16 Sping Boot 入门 Sping框架--Java Web之书城项目 dingda模块

D17 Sping Boot 入门 Sping框架--Java Web之Filter过滤器

D17 Sping Boot 入门 Sping框架--Java Web之Filter过滤器