Springboot可以简化spring应用程序的创建和开发过程,也可以说Springboot可以大大简化之前SSM(SpringMVC+Spring+Mybatis)的框架进行开发的过程。它可以省去之前繁琐的编辑配置文件的过程,采用 大量的默认配置 来简化开发过程。
正因为上述的优点,Springboot可以非常容易和快速地创建基于Spring框架的应用程序,使得编码、配置、部署和监控都变得简单了,因此它在业界备受关注。
21、能够快速创建基于Spring的程序
22 能够直接使用java main方法启动内嵌的Tomcat服务器运行Springboot程序,不需要部署war文件
23 提供约定的starter POM来简化Maven配置,使得这个过程更加简单
24 自动化配置,根据项目的Maven依赖配置,springboot可以自动配置Spring、SpringMVC等等
25 提供了程序的健康检查功能
26 基本可以完全不使用XML配置文件,采用注解来配置
31 自动配置
32 起步依赖
springboot的优点就是简化配置,,没有了xml,基本都是一个配置(applicationproperties)+注解来实现springboot的构建
那么都有哪些注解咧说一下我在工作中常用的注解
1:##@SpringBootApplication
标识该类为SpringBoot项目启动类。并且让SpringBoot自动给程序进行必要的配置,等同于@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个注解
(1):@SpringBootConfiguration表示的是该类会作为Springboot的一个配置类,
(2):@EnableAutoConfiguration表示开启自动配置功能,里面也实现了自动配置原理
@Configuration会把组件会装配到实体类上封装为一个bean,AutoConfigurationImportSelector的selectImports()这个方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。bean有了,配置有了,相当于对象也有了,这就是自动配置
(3):@ComponentScan用来将包加入SpringIOC的包扫描,
2: @RestController 和@Controller
@RestController相当于@Controller+@ResponseBody,
@RestController加在类上面的注解,使得类里面的每个方法都将json/xml返回数据加返回到前台页面中。
比如return "abc" 前端会展示abc三个字母
@Controller加在类上面的注解,使得类里面的每个方法都返回一个视图页面。
比如return "abc" 前端会展示静态资源中的的abchtml里面的内容
3: @component和@configuration
虽然Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class,所以在生成Driver对象时和生成Car对象时调用car()方法执行了两次new *** 作,所以是不同的对象。当时Configuration注解时,生成当前对象的子类Class,并对方法拦截,第二次调用car()方法时直接从BeanFactory之中获取对象,所以得到的是同一个对象。
4: @Autowired 与@Resource
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javaxannotationResource,需要导入,但是Spring支持该注解的注入。
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用
@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javaxannotationResource。
以上是一个最简单的Springboot程序(203版本)示例,也是我们最通用的写法,但其中其实封装这一系列复杂的功能 *** 作,让我们开始逐步进行分析。
首先这里最重要的必然是注解 @SpringBootApplication
@SpringBootApplication 注解由几个注解复合组成,其中最主要的就是 @SpringBootConfiguration 、 @EnableAutoConfiguration 和 @ComponentScan 这三个。
其中的 @ComponentScan 是spring的原生注解, @SpringBootConfiguration 虽然是springboot中的注解,但其实质就是包装后的 @Configuration ,仍然是spring中的注解,用于代替xml的方式管理配置bean
@EnableAutoConfiguration 的定义如上,这里最重要的注解是 @Import ( @AutoConfigurationPackage 注解的实现也是基于 @Import ),借助 @Import 的帮助,将所有符合自动配置条件的bean定义加载到IoC容器中。关于 @EnableAutoConfiguration 注解后续涉及到时会再详细说明。这里我们先回到启动类的 run 方法从头分析初始化流程。
可以看到'run'方法最终调用的是 new SpringApplication(primarySources)run(args) ,这里首先创建了 SpringApplication 对象,然后调用其 run 方法
这里主要是为 SpringApplication 对象进行初始化,这里要专门提一下的是 webApplicationType 和 getSpringFactoriesInstances 。
它用来标识我们的应用是什么类型的应用,来看一下 deduceWebApplicationType() 方法的实现
其返回值是 WebApplicationType 类型的枚举类,其值有 NONE 、 SERVLET 、 REACTIVE 三种,分别对应非WEB应用,基于servlet的WEB应用和基于reactive的WEB应用。
这里的核心是 SpringFactoriesLoaderloadFactoryNames(type, classLoader) 方法,来看一下
重点关注一下 loadSpringFactories(classLoader) 做了什么
这里的 FACTORIES_RESOURCE_LOCATION 定义为 META-INF/springfactories ,因此该方法会扫描所有包下的该文件,将其解析成map对象并缓存到 cache 中以避免重复加载,springboot包下该文件的部分片段如下
从这里可以看出, setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializerclass)) 和 setListeners((Collection) getSpringFactoriesInstances(ApplicationListenerclass)); 分别对应设置的是上述这些类。
解析完成后调用 createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names) 处理解析结果,生成对应的实例,源码如下
这里的核心是通过 ClassUtilsforName(name, classLoader) 方法,以反射的方式生成类实例 instanceClass 。由此可以看出 SpringFactoriesLoaderloadFactoryNames(type, classLoader) 的作用就是将 META-INF/springfactories 中配置的内容进行实例化的工厂方法类,具备很强的扩展性,与SPI机制有异曲同工
的效果。
看完 SpringApplication 的初始化,接着跳回 run 方法继续分析
这里挑其中比较重要的几个方法进行分析
通过 getOrCreateEnvironment() 方法创建容器环境
可以看到 environment 存在则不会重复创建,当应用类型为servlet时创建的是 StandardServletEnvironment 对象,否则创建 StandardEnvironment 对象。
接着来看 configureEnvironment(environment, applicationArgumentsgetSourceArgs())
configurePropertySources(environment, args) 加载启动命令行的配置属性,来看一下实现
这里的 MutablePropertySources 对象用于存储配置集合,其内部维护了一个 CopyOnWriteArrayList 类型的list对象,当默认配置存在时,会向该list的尾部插入一个 new MapPropertySource("defaultProperties", thisdefaultProperties) 对象。
接着来看 configureProfiles(environment, args)
这里主要做的事情就是获取 environmentgetActiveProfiles() 的参数设置到 environment 中,即 springprofilesactive 对应的环境变量。
最后来看一下 listenersenvironmentPrepared(environment)
这里的 listeners 就是之前通过 META-INF/springfactories 注册的所有listeners,后面我们先以其中最重要的 ConfigFileApplicationListener 做为例子进行分析,接着来看 listenerenvironmentPrepared(environment)
可以看到这里创建了一个 ApplicationEnvironmentPreparedEvent 类型的事件,并且调用了 multicastEvent 方法,通过该方法最终会调用到listener的 onApplicationEvent 方法,触发事件监听器的执行。
接下来具体看一下 ConfigFileApplicationListener 的 onApplicationEvent 方法做了什么
可以看到当监听到 ApplicationEnvironmentPreparedEvent 类型的事件时,调用 onApplicationEnvironmentPreparedEvent( (ApplicationEnvironmentPreparedEvent) event) 方法
可以看到这里通过 loadPostProcessors() 方法加载了 META-INF/springfactories 中的所有 EnvironmentPostProcessor 类到list中,同时把 ConfigFileApplicationListener 自己也添加进去了。接着遍历list中所有对象,并执行 postProcessEnvironment 方法,于是接着来看该方法
这里的核心是 new Loader(environment, resourceLoader)load() ,这里的 Loader 是一个内部类,用于处理配置文件的加载,首先看一下其构造方法
可以看到这里的 resourceLoader 又是通过 SpringFactoriesLoader 进行加载,那么来看看 META-INF/springfactories 中定义了哪些 resourceLoader
从名字就可以看出来, PropertiesPropertySourceLoader 和 YamlPropertySourceLoader 分别用于处理properties和yml类型的配置文件。
接着来看看 load() 方法做了什么
initializeProfiles() 进行了 profiles 的初始化,默认会添加 null 和 default 到 profiles 中, null 对应配置文件applicationproperties和applicationyml, default 对应配置文件application-defaultyml和application-defaultproperties,这里的 null 会被优先处理,由于后处理的会覆盖先处理的,因此其优先级最低。
接着来看 load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false)) 方法
这里重点是通过 getSearchLocations() 获取配置文件的路径,默认会获得4个路径
接着会遍历这些路径,拼接配置文件名称,选择合适的yml或者properties解析器进行解析,最后将结果添加到 environment 的 propertySources 中。
可以看到这里也是根据 webApplicationType 的取值,分别创建不同的返回类型。
这里的 sources 装的就是我们的启动类,然后通过 load(context, sourcestoArray(new Object[0])) 方法进行加载
来看一下 loader 是如何被加载的
经过一系列调用之后最终由 load(Class<> source) 方法执行,这里比较有趣的是当Groovy存在时居然是优先调用Groovy的方式进行加载,否则才走 thisannotatedReaderregister(source) 方法将启动类注册到 beanDefinitionMap 中。
这个 refresh() 方法相当重要,尤其是 invokeBeanFactoryPostProcessors(beanFactory) ,这是实现spring-boot-starter-(mybatis、redis等)自动化配置的关键部分,后续再详细讲解。
至此Springboot的启动流程已经大体分析完了,也了解了配置文件和启动类分别是是如何被加载的,但仍有两个问题待解,一是Springboot的核心思想约定大于配置是如何做到的,二是Springboot的各种spring-boot-starter-是如何发挥作用的,这两个问题留待后续文章继续分析。
springboot 本身支持多种灵活的配置方式,为开发 springboot 程序带来了很大的灵活性和扩展性,但是同时由于太灵活,经常会导致明明配置了相关属性,却没有生效。
本文总结了 springboot 配置文件的原理以及多个配置文件生效的顺序。
springboot 配置文件支持灵活的路径,以及灵活的文件名,用一个变量表达式总结如下:
部分源码如下:
当满足上述变量表达式的配置文件有多个时,会有一个配置的优先级。假设
上面每个条件组合起来,则最多有配置文件如下,且顺序从上到下:
获取属性时,按从上到下的顺序遍历由上述文件生成的属性资源对象 PropertySource ,如果遇到匹配的key直接返回。
总结一下:就是如果同一个key的属性只出现一次,则直接取该值即可。如果同一个key的属性出现多次,则取顺序靠前的属性资源对象。另外其中每个文件都是可选的。
需要注意的一点是:如果在同一个 location 下配置了多个文件名一样的文件,则只会取一个,比如在 classpath:/ ,有如下两个文件 applicationyml :
则只会根据 classloader 的 classpath 列表,选取第一个出现的文件。因为 springboot 加载配置文件时最底层是使用的下面的方法:
这两个方法只会获取 classloader 类的 ucp 属性里面第一个匹配到的值。如果对 springboot 自身的机制不满意,想获取所有的classpath:/路径下面的 applicaitonyml 文件,可以使用下面的方法:
本文总结了 springboot 配置文件的原理以及多个配置文件生效的顺序。如果存在增加了配置文件或者在配置文件里面增加了属性却没有生效,可以参考上面的 springboot 配置文件表达式和配置文件生效顺序进行排查。
后面还会有一篇文章讨论基于 springboot 配置原理如何实现自定义的配置读取方式。
前端要获取后端的值,需要在后端提供服务接口API,然后前端通过>
以上就是关于Springboot简介全部的内容,包括:Springboot简介、Springboot(四):springboot的注解有哪些注解、Springboot初始化流程解析等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)