当前位置:首页 > 洗衣机 > 文章正文

细说SpringBoot的自动装配事理

编辑:[db:作者] 时间:2024-08-25 05:24:18

  springboot框架是为了能够帮助利用spring框架的开拓者快速高效的构建一个基于spirng框架以及spring生态体系的运用办理方案。
它是对“约定优于配置”这个理念下的一个最佳实践。

细说SpringBoot的自动装配事理

因此它是一个做事于框架的框架,做事的范围是简化配置文件。

2.初步认识Spring Boot

  我们可以利用 https://start.spring.io

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

  为了让大家看到效果,我们利用spring mvc来构建一个web运用,而springboot帮我们简化了非常多的逻辑使得我们非常随意马虎去构建一个web项目。

  springboot供应了spring-boot-starter-web自动装置模块

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>1234

  在当前项眼前运行mvn spring-boot:run 或者直接运行main方法就可以启动一个利用了嵌入式tomcat做事要求的web运用,但是我们没有供应任何做事web要求的controller,以是访问任何路径都会返回一个springboot默认的缺点页面(whitelabel error page)

  以是,我们可以创建一个Controller来实现要求

@RestControllerpublic class HelloController { @GetMapping("/say") public String sayHello(){ return "hello Mic"; }}

  访问http://localhost:8080/say 就可以得到一个要求结果。
这样就完成了一个非常大略的web运用。
springboot是一个约定优于配置的产物,以是在快速构建web运用的背后,实在有很多的约定。

项目构造层面,静态文件和页面模版的存放位置变成了src/main/resources对应的子目录下自动嵌入tomcat作为web容器对外供应http做事,默认利用8080端口监听自动装置springmvc必要的组件3.Spring Boot四大核心

EnableAutoConfiguration 自动装置Starter组件, 开箱即用Actuator 监控Spring Boot Cli 为Spring Cloud 供应了Spring Boot 命令行功能

  那今天主要给大家讲讲Enable这个表明

4.Enable 表明的浸染

  Enable是启用的意思,相称于开启某一个功能

EnableSchedulingEnableHystrixEnableAsyncEnableAutoConfigurationEnableWebMvc

  仍旧是在spring3.1版本中,供应了一系列的@Enable开头的表明,Enable主机该当是在JavaConfig框架上更进一步的完善,是的用户在利用spring干系的框架是,避免配置大量的代码从而降落利用的难度

  比如常见的一些Enable表明:EnableWebMvc,(这个表明引入了MVC框架在Spring 运用中须要用到的所有bean);

  比如说@EnableScheduling,开启操持任务的支持;

  找到EnableAutoConfiguration,我们可以看到每一个涉及到Enable开头的表明,都会带有一个@Import的表明。

5.深入剖析Spring Boot中的自动装置

  在Spring Boot中,不得不说的一个点是自动装置,它是starter的根本,也是Spring Boot的核心, 那什么叫自动装置?或者什么叫装置呢?

  回顾一下Spring Framework,它最核心的功能是IOC和AOP, IoC容器的紧张功能是可以管理工具的生命周期。
也便是bean的管理。
我们把Bean工具托管到Spring Ioc容器的这个过程称为装置,那什么是自动装置呢?我们逐步来先容

  首先大家看下这张图,我们先不阐明。
等把本日的内容讲完,我们再转头来通过这张图来总结~

  自动装置在SpringBoot是基于EnableAutoConfiguration来实现的。
那么在深入剖析EnableAutoConfiguration之前,我们来看一下传统意义上的装置办法。

5.1大略剖析@Configuration

  Configuration这个表明大家该当有用过,它是JavaConfig形式的基于Spring IOC容器的配置类利用的一种表明。
由于SpringBoot实质上便是一个spring运用,以是通过这个表明来加载IOC容器的配置是很正常的。
以是在启动类里面标注了@Configuration,意味着它实在也是一个IoC容器的配置类。

public class DemoClass { public void say(){ System.out.println("sya hello ... "); }}

@Configuration@Import(UserClass.class)public class DemoConfiguration { @Bean public DemoClass getDemoClass(){ return new DemoClass(); }}

public class DemoConfigurationMain { public static void main(String[] args) { ApplicationContext ac = new AnnotationConfigApplicationContext(DemoConfiguration.class); DemoClass bean = ac.getBean(DemoClass.class); bean.say(); }}

  这种形式便是通过表明的办法来实现IoC容器,传统意义上的spring运用都是基于xml形式来配置bean的依赖关系。
然后通过spring容器在启动的时候,把bean进行初始化并且,如果bean之间存在依赖关系,则剖析这些已经在IoC容器中的bean根据依赖关系进行组装。

  直到Java5中,引入了Annotations这个特性,Spring框架也紧随大流并且推出了基于Java代码和Annotation元信息的依赖关系绑定描述的办法。
也便是JavaConfig。

  从spring3开始,spring就支持了两种bean的配置办法,一种是基于xml文件办法、另一种便是JavaConfig

Configuration的实质

  如果大家细心一点就会创造Configuration表明的实质是一个Component表明,这个表明会被AnnotationConfigApplicationContext加载,而AnnotationConfigApplicationContext是ApplicationContext的一个详细实现,表示根据配置表明启动运用高下文。
  因此我们在Main方法中通过AnnotationConfigApplicationContext去加载JavaConfig后,可以得到Ioc容器中的bean的实例  JavaConfig的办法在前面的代码中已经演示过了,任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。
而在这个配置类中,任何标注了@Bean的方法,它的返回值都会作为Bean定义注册到Spring的IOC容器,方法名默认成为这个bean的id

5.2大略剖析@ComponentScan

  ComponentScan这个表明是大家打仗得最多的了,相称于xml配置文件中的<context:component-scan>。
它的紧张浸染便是扫描指定路径下的标识了须要装置的类,自动装置到spring的Ioc容器中。

  标识须要装置的类的形式紧张是:@Component、@Repository、@Service、@Controller这类的表明标识的类。

public static void main(String[] args) { ApplicationContext ac = new AnnotationConfigApplicationContext(DemoConfiguration.class); String[] beanDefinitionNames = ac.getBeanDefinitionNames(); System.out.println(""); for (String beanName:beanDefinitionNames ) { System.out.println(beanName); }}5.3 Import表明

  import 表明是什么意思呢? 遐想到xml形式下有一个<import resource/> 形式的表明,就明白它的浸染了。
import便是把多个分开的容器配置合并在一个配置中。
在JavaConfig中所表达的意义是一样的。
为了能更好的理解后面讲的EnableAutoConfiguration,我们详细地和大家来先容下import表明的利用

办法一:直接填class数组

  我们先在不同的两个package下创建对应的bean。
  比如:

  那么DemoConfigurationMain中实行的代码该当是加载不到demo2中的UserClass的

  这时我们可以通过@import来直接加载

或者

办法二:ImportSelector办法【重点】

  第一种办法如果导入的是一个配置类,那么该配置类中的所有的都会加载,如果想要更加的灵巧,动态的去加载的话可以通过Import接口的第二种利用办法,也便是ImportSelector这种办法,我们来看看怎么利用。
LogService

public class LogService {}

CacheService

public class CacheService {}

GpDefineImportSelector

public class GpDefineImportSelector implements ImportSelector { / AnnotationMetadata 表明元数据 @param annotationMetadata @return 要被IOC容器加载的bean信息 / @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 我们可以基于表明元数据信息来动态的返回要加载的bean信息 annotationMetadata .getAllAnnotationAttributes(EnableDefineService.class.getName(),true) .forEach((k,v)->{ System.out.println(annotationMetadata.getClassName()); System.out.println("---> " + k+":" + String.valueOf(v)); }); return new String[]{CacheService.class.getName()}; }}

EnableDefineService

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(GpDefineImportSelector.class)public @interface EnableDefineService { String[] packages() default "";}

EnableDemoTest

@EnableDefineService()@SpringBootApplicationpublic class EnableDemoTest { public static void main(String[] args) { ApplicationContext ac = new AnnotationConfigApplicationContext(EnableDemoTest.class);//SpringApplication.run(EnableDemoTest.class,args); System.out.println(ac.getBean(CacheService.class)); System.out.println(ac.getBean(LogService.class)); }}办法三:ImportBeanDefinitionRegistrar办法

  这种办法和第二种办法很相似,同样的要实现 ImportBeanDefinitionRegistrar 接口

public class GpImportDefinitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { // 指定bean的定义信息 RootBeanDefinition beanDefinition = new RootBeanDefinition(CacheService.class); RootBeanDefinition beanDefinition1 = new RootBeanDefinition(LogService.class); // 注册一个bean beanDefinitionRegistry.registerBeanDefinition("cacheService1111",beanDefinition); beanDefinitionRegistry.registerBeanDefinition("cacheService2222",beanDefinition1); }}

5.4 深入剖析EnableAutoConfiguration事理

  理解了ImportSelector和ImportBeanDefinitionRegistrar后,对付EnableAutoConfiguration的理解就随意马虎一些了  它会通过import导入第三方供应的bean的配置类:AutoConfigurationImportSelector

AutoConfigurationImportSelector

public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { try {// 加载META-INF/spring-autoconfigure-metadata.properties 下的元数据信息 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 获取候选加载的配置信息 META-INF/spring.factories List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);// 去掉重复的配置信息 configurations = this.removeDuplicates(configurations);// 排序 configurations = this.sort(configurations, autoConfigurationMetadata); // 获取 表明中配置的 exclusion 信息Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);// 检讨 this.checkExcludedClasses(configurations, exclusions);// 移除须要打消的信息 configurations.removeAll(exclusions);// 过滤,检讨候选配置类上的表明@ConditionalOnClass,如果哀求的类不存在,则这个候选类会被过滤不被加载 configurations = this.filter(configurations, autoConfigurationMetadata);// 广播事宜 this.fireAutoConfigurationImportEvents(configurations, exclusions); // 返回要被加载的类数组return (String[])configurations.toArray(new String[configurations.size()]); } catch (IOException var6) { throw new IllegalStateException(var6); } }}1234567891011121314151617181920212223242526272829303132

  实质上来说,实在EnableAutoConfiguration会帮助springboot运用把所有符合@Configuration配置都加载到当前SpringBoot创建的IoC容器,而这里面借助了Spring框架供应的一个工具类SpringFactoriesLoader的支持。
以及用到了Spring供应的条件表明@Conditional,选择性地针对须要加载的bean进行条件过滤

5.5 SpringFactoriesLoader

  为了给大家补一下根本,我在这里大略剖析一下SpringFactoriesLoader这个工具类的利用。
它实在和java中的SPI机制的事理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据key进行加载。

  首先,SpringFactoriesLoader的浸染是从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。
接下来带大家实践一下  通过mybatis整合来看  引入mybatis的依赖

<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.2</version></dependency>12345

  查看 MybatisAutoConfiguration 里面的源码,创造在个中加载了SqlSessionFactory等信息。

通过实际案例来实现

  创建一个新的maven项目,引入干系的依赖

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6.RELEASE</version> </dependency></dependencies>1234567

创建一个bean类

public class GpCoreService { public void crudService(){ System.out.println("gupao core service run ..."); }}

以及对应的配置类

@Configurationpublic class GpConfiguration { @Bean public GpCoreService gpCoreService(){ return new GpCoreService(); }}

然后打包

在另一个项目中导入该jar包

<dependency> <groupId>org.gupao.edu</groupId> <artifactId>Gp-Core</artifactId> <version>1.0-SNAPSHOT</version></dependency>12345

  通过下面代码获取依赖包中的属性

  运行结果会报错,缘故原由是GuPaoCore并没有被Spring的IoC容器所加载,也便是没有被EnableAutoConfiguration导入

public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args); String[] beanDefinitionNames = run.getBeanDefinitionNames(); System.out.println(run.getBean(GpCoreService.class));}

办理方案

  在GuPao-Core项目resources下新建文件夹META-INF,在文件夹下面新建spring.factories文件,文件中配置,key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gupao.edu.GpConfiguration

  重新打包,重新运行SpringBootStudyApplication这个类。
  可以创造,我们编写的那个类,就被加载进来了。

5.6深入理解条件过滤

  在剖析AutoConfigurationImportSelector的源码时,会先扫描spring-autoconfiguration-metadata.properties文件,末了在扫描spring.factories对应的类时,会结合前面的元数据进行过滤,为什么要过滤呢? 缘故原由是很多的@Configuration实在是依托于其他的框架来加载的,如果当前的classpath环境下没有干系联的依赖,则意味着这些类没必要进行加载,以是,通过这种条件过滤可以有效的减少@configuration类的数量从而降落SpringBoot的启动韶光。
  修正Gupao-Core

  在META-INF/增加配置文件,spring-autoconfigure-metadata.properties。

com.gupao.edu.GpConfiguration.ConditionalOnClass=com.gupao.edu.service.GpTestService

格式:自动配置的类全名.条件=值

上面这段代码的意思便是,如果当前的classpath下存在TestClass,则会对GuPaoConfig这个Configuration进行加载演示过程(spring-boot)

1.沿用前面spring-boot工程的测试案例,直接运行main方法,创造原来能够被加载的GuPaoCore,创造在ioc容器中找不到了。
2.在当前工程中指定的包com.gupaoedu下创建一个TestClass往后,再运行上面这段代码,程序能够正常实行

好了~到此如果随着一块动手的话相信你对付SpringBoot的自动装置该当有了不一样的理解

本站所发布的文字与图片素材为非商业目的改编或整理,版权归原作者所有,如侵权或涉及违法,请联系我们删除,如需转载请保留原文地址:http://www.baanla.com/xyj/139511.html

XML地图 | 自定链接

Copyright 2005-20203 www.baidu.com 版权所有 | 琼ICP备2023011765号-4 | 统计代码

声明:本站所有内容均只可用于学习参考,信息与图片素材来源于互联网,如内容侵权与违规,请与本站联系,将在三个工作日内处理,联系邮箱:123456789@qq.com