SpringBoot-1(springboot基本配置,SpringJavaConfig)

一、Spring Boot 简介

     Spring Boot Spring 家族中的一个全新的框架,它用来简化 Spring 应用程序的创建和
开发过程,也可以说 Spring Boot 能简化我们之前采用 SpringMVC + Spring + MyBatis 框架进行
开发的过程。
     在以往我们采用 SpringMVC + Spring + MyBatis 框架进行开发的时候,搭建和整合三大框
架,我们需要做很多工作,比如配置 web.xml ,配置 Spring ,配置 MyBatis ,并将它们整合在
一起等,而 Spring Boot 框架对此开发过程进行了革命性的颠覆,完全抛弃了繁琐的 xml
置过程,采用大量的默认配置简化我们的开发过程。
     所以采用 Spring Boot 可以非常容易和快速地创建基于 Spring 框架的应用程序,它让编
码变简单了,配置变简单了,部署变简单了,监控变简单了。正因为 Spring Boot 它化繁为
简,让开发变得极其简单和快速,所以在业界备受关注。

     SpringBoot是Spring团队在2014年,伴随Spring4.0版本推出的一个新的框架。

https://spring.io/

主要作用:

SpringBoot使创建独立的、生产级的、基于Spring的应用程序变得容易,您可以“只运行”。

就是帮助我们快速的创建出基于Spring的应用程序。

想一想在你没有SpringBoot的时候我们使用Spring创建应用程序,或者是整合SpringMVC、MyBatyis,往往都需要先导入很多的依赖包,然后编写大量的配置文件,然后开发业务逻辑,最后测试,接下来就是打war包,部署到服务器,部署之前还得配置好服务器环境,这样才完成工作。所以在以前没有SpringBoot的时候,我们对java EE程序的开发都是比较笨重的开发,需要繁多的配置,带来低下的开发效率和复杂的部署流程,还有第三方技术集成难度大。因此上SpringBoot的出现实际上就是用来简化我们对java EE程序的开发,帮助我们快速的创建出基于Spring的应用程序。

SpringBoot的底层实际上还是使用的Spring技术,他其实就是通过整合Spring提供的针对不同领域的开发框架来达到简化Java EE 程序的开发步骤的

Spring提供的针对不同领域的开发框架:

Spring Framework:提供IOC容器

Spring Cloud:分布式框架

Spring Data:数据库访问框架

Spring Security:安全校验框架

等等......

SpringBoot--帮助我们快速的创建出基于Spring框架的应用程序的一个框架。利用SpringBoot创建的Spring应用程序,可以很轻松的实现Spring各种子框架的应用和整合。

二、Spring Boot 的特性

1.能够快速创建基于 Spring 的应用程序
 
2.能够直接使用 java main 方法启动内嵌的 Tomcat 服务器运行 Spring Boot 程序,不需
要部署 war 包文件
 
3.提供约定的 starter POM 来简化 Maven 配置,让 Maven 的配置变得简单
 
4.自动化配置,根据项目的 Maven 依赖配置, Spring boot 自动配置 Spring Spring mvc
 
5.提供了程序的健康检查等功能
 
6.基本可以完全不使用 XML 配置文件,采用注解配置

Spring Boot 四大核心

自动配置
 
起步依赖
 
Actuator
 
命令行界面

三、微服务(Microservice)是什么?

SOA(面向服务的架构)

微服务,是与之前的服务化思路和实践相比较而来的。
早些年的服务实现和实施思路是将很多功能从开发到交付都打包成一个很大的服务单元(一般称为 Monolith),而微服务实现和实施思路则更强调功能趋向单一,服务单元小型化和微型化。
如果用“茶壶煮饺子”来打比方的话,原来我们是在一个茶壶里煮很多个饺子,现在(微服务化之后)则基本上是在一个茶壶煮一个饺子,而这些饺子就是服务的功能,茶壶则是将这些服务功能打包交付的服务单元,如图 1 所示。

     所以,从思路和理念上来讲,微服务就是要倡导大家尽量将功能进行拆分,将服务粒度做小,使之可以独立承担对外服务的职责,沿着这个思路开发和交付的软件服务实体就叫作“微服务”,而围绕着这个思路和理念构建的一系列基础设施和指导思想,笔者将它称为“微服务体系”。

微服务是怎么来的?

     微服务的概念我们应该大体了解了,那么微服务又是怎么来的?原来将很多功能打包为一个很大的服务单元进行交付的做法不能满足需求吗?
     实际上,并非原来“大一统”(Monolith)的服务化实践不能满足要求,也不是不好,只是,它有自己存在的合理场景。
对于 Monolith 服务来说,如果团队不大,软件复杂度不高,那么,使用 Monolith 的形式进行服务化治理是比较合适的,而且,这种方式对运维和各种基础设施的要求也不高。
但是,随着软件系统的复杂度持续飙升,软件交付的效率要求更高,投入的人力以及各项资源越来越多,基于 Monolith 的服务化思路就开始“捉襟见肘”。
     在开发阶段,如果我们遵循 Monolith 的服务化理念,通常会将所有功能的实现都统一归到一个开发项目下,但随着功能的膨胀,这些功能一定会分发给不同的研发人员进行开发,造成的后果就是,大家在提交代码的时候频繁冲突并需要解决这些冲突,单一的开发项目成为了开发期间所有人的工作瓶颈。
为了减轻这种苦恼,我们自然会将项目按照要开发的功能拆分为不同的项目,从而负责不同功能的研发人员就可以在自己的代码项目上进行开发,从而解决了大家无法在开发阶段并行开发的苦恼。
到了软件交付阶段,如果我们遵循 Monolith 的服务化理念,那么,我们一定是将所有这些开发阶段并行开发的项目集合到一起进行交付。
     这就涉及服务化早期实践中比较有名的“火车模型”,即交付的服务就像一辆火车,而这个服务相关的所有功能对应的项目成果,就是要装上火车车厢的一件件货物,交付的列车只有等到所有项目都开发测试完成后才可以装车出发,完成整个服务的交付。
     很显然,只要有一个车厢没有准备好货物(即功能项目未开发测试完成),火车就不能发车,服务就不能交付,这大大降低了服务的交付效率。如果每个功能项目可以各自独立交付,那么就不需要都等同一辆火车,各自出发就可以了。
顺着这个思路,自然而然地,大家逐渐各自独立,每一个功能或者少数相近的功能作为单一项目开发完成后将作为一个独立的服务单元进行交付,从而在服务交付阶段,大家也能够并行不悖,各自演化而不受影响。
所以,随着服务和系统的复杂度逐渐飙升,为了能够在整个软件的交付链路上高效扩展,将独立的功能和服务单元进行拆分,从而形成一个一个的微服务是自然而然发生的事情。
这就像打不同的战役一样,在双方兵力不多、战场复杂度不高的情况下,Monolith 的统一指挥调度方式是合适的。而一旦要打大的战役(类似于系统复杂度提升),双方一定会投入大量的兵力(软件研发团队的规模增长),如果还是在狭小甚至固定的战场上进行厮杀,显然施展不开!
     所以,小战役有小战役的打法,大战役有大战役的战法,而微服务实际上就是一种帮助扩展组织能力、提升团队效率的应对“大战役”的方法,它帮助我们从软件开发到交付,进而到团队和组织层面多方位进行扩展。
总的来说,一方面微服务可以帮助我们应对飙升的系统复杂度;另一个方面,微服务可以帮助我们进行更大范围的扩展,从开发阶段项目并行开发的扩展,到交付阶段并行交付的扩展,再到相应的组织结构和组织能力的扩展,皆因微服务而受惠。

     早期我们从开发到交付,都是单一应用结构,所有功能都集中在一个项目中,统一管理和开发。【雕版印刷】

     微服务就是一个项目中的功能,独立的分成多个子项目,并行开发。【活字印刷】

     微服务其实是一种架构风格,提倡一个应用应该是一组小型服务组成;可以通过HTTP的方式进行互通。

     在没有微服务之前我们软件架构方式称为单体应用:ALL IN ONE。就是所有的内容统一集中在一个应用程序中。

     这种单体应用的优点:开发测试简单,不会涉及多个应用之间的互联互调,应用部署也简单,只需要一个war包就OK,不会对运维造成太大负担,还有就是应用程序的水平扩展也简单,就是新增模块简单。当并发量高的时候,我们可以将这个单体应用多复制几份部署在多个服务器上,通过负载均衡机制控制运行,可以提高并发访问。

     他的缺点也很明显,那就是到我们需要对程序进行修改的时候就需要重新打包,重新部署,重新运行,这就是一个牵一发动全身的情况,当然更大的挑战是来自于日益增长的软件需求。

 

     目前我们随便做一个软件都需要提供很多更能,不管这些功能有用没有都得实现,这个一个小应用就都成一个大型应用。而大型应用我们不可能将所有功能全部都写在一个应用中,因为分工合作麻烦,维护量大,而且这个应用到时候可能谁都不知道这个应用会有多大。所以我们才要学习使用微服务开发,来避免这样的问题。

可以这样理解:

     单体应用就是雕版印刷

     微服务就是活字印刷

     微服务:每一个功能元素最终都是一个可独立替换和独立升级的软件单元;

     那么利用微服务搭建起来的项目长什么样?

这种类似于神经网络一样的结构就是最终微服务构建起来的项目,每一个圆圈就是服务,服务于服务之间通过http协议访问连接。

那么这种庞大微服务应用程序如何构建和部署整合呢,这时我们的SPringBoot就有用武之地。

通过SpringBoot快速构建微服务应用,通过SpringCloud进行分布式互联互调,形成分布式结构,通过SpringCloudDataFlow进行流式数据运算和批处理操作。

四、SpringBoot 输出HelloWorld

     需求:浏览器发送hello请求,服务器接受请求并处理,响应Hello World字符串。

    1.创建一个maven工程;(jar)

一路next直至项目创建成功!

2.pom文件配置

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

可以帮助我们将开发基于Spring的web应用程序的所有依赖包全部自动导入

3..在src/main/java下创建控制器类

package com.wangxing.springboot.controller;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
    @RequestMapping(value = "/test")
    @ResponseBody
    public String  testController(){
      String info="hello,网星";
      return info;
    }
}

4.由于我们自己创建的控制器类与SpringBoot的主类不在同一个包中,所以我们需要给主类

package com.wangxing.springboot.springbootdemo1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.wangxing.springboot.controller")
public class Springbootdemo1Application {

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


}

5.运行主类中的主方法,应用程序自动部署,内嵌的Servlet容器自动启动 

打开浏览器访问

http://localhost:8080/hello

6.将上面的用户程序打成jar包,通过java -jar xxxxx.jar命令来执行

成功以后会在当前项目的target中生成对应的jar包

将这个jar包复制出去,编写一个与之对应的批处理文件,双击就可运行。

打开浏览器访问

五、Spring JavaConfig

     Java 5 的推出,加上当年基于纯 Java Annotation 的依赖注入框架 Guice 的出现,推出并持续完善了基于 Java 代码和 Annotation 元信息的依赖关系绑定描述方式,即 JavaConfig 项目。
    基于 JavaConfig 方式的依赖关系绑定描述基本上映射了最早的基于 XML 的配置方式,比如:

1)表达形式层面

基于 XML 的配置方式是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="stubean" class="com.wangxing.javaconfigdemo1.StudentBean"></bean>
</beans>

而基于 JavaConfig 的配置方式是这样的:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class StudentConfig {
    @Bean
    public StudentBean stubean(){
        return new StudentBean();
    }
}

    任何一个标注了 @Configuration 的 Java 类定义都是一个 JavaConfig 配置类。

    任何一个标注了 @Bean 的方法,其返回值将作为一个 bean 定义注册到 Spring 的 IoC 容器,方法名将默认成为该 bean 定义的 id。

package com.wangxing.javaconfigdemo1;

import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {
    @Test
    public void test1() {
        ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
        StudentBean studentBean=(StudentBean)context.getBean("stubean");
        studentBean.testStudent();
    }
}

1)构造方法注入

package com.wangxing.javaconfigdemo1;
public class PersonBean {
    public void  testPerson(){
        System.out.println("PersonBean类的testPerson方法");
    }
}
package com.wangxing.javaconfigdemo1;

public class StudentBean {

    private PersonBean personBean;

    public  StudentBean(PersonBean personBean) {
        this.personBean = personBean;
    }
    public void  methodStudent(){
        personBean.testPerson();
        System.out.println("Student类的methodStudent方法");
    }
}

在 XML 形式中一般是这样的:

<bean id="perbean" class="com.wangxing.javaconfigdemo1.PersonBean" />

<bean id="stubean" class="com.wangxing.javaconfigdemo1.StudentBean">

    <!-- 构造方法注入配置  -->

</bean>

而在 JavaConfig 中则是这样的:

@Configuration
public class StudentConfig {
    @Bean
    public PersonBean perbean(){
        return new PersonBean();
    }
    @Bean
    public StudentBean stubean(){
        return new StudentBean(perbean());
    }
}

2)set方法注入

package com.wangxing.javaconfigdemo1;
public class PersonBean {
    public void  testPerson(){
        System.out.println("PersonBean类的testPerson方法");
    }
}
package com.wangxing.javaconfigdemo1;
public class StudentBean {
    private PersonBean personBean;

    public void setPersonBean(PersonBean personBean) {
        this.personBean = personBean;
    }
    public void  methodStudent(){
        personBean.testPerson();
        System.out.println("Student类的methodStudent方法");
    }
}

在 XML 形式中一般是这样的:

<bean id="perbean" class="com.wangxing.javaconfigdemo1.PersonBean" /> 
<bean id="stubean" class="com.wangxing.javaconfigdemo1.StudentBean">
   	<!-- set方法注入配置  -->
</bean>

而在 JavaConfig 中则是这样的:

package com.wangxing.javaconfigdemo1;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StudentConfig {
    @Bean
    public PersonBean perbean(){
        return new PersonBean();
    }
    @Bean
    public StudentBean stubean(){
        StudentBean studentBean=new StudentBean();
        studentBean.setPersonBean(perbean());
        return studentBean;
    }
}

测试

@Test
public void test1() {
    ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
    StudentBean studentBean=(StudentBean)context.getBean("stubean");
    //studentBean.testStudent();
    studentBean.methodStudent();
}

     如果一个 bean 的定义依赖其他 bean,则直接调用对应 JavaConfig 类中依赖 bean 的创建方法就可以了。
在 JavaConfig 形式的依赖注入过程中,我们使用方法调用的形式注入依赖,如果这个方法返回的对象实例只被一个 bean 依赖注入,那也还好,如果多于一个 bean 需要依赖这个方法调用返回的对象实例,那是不是意味着我们就会创建多个同一类型的对象实例?
     从代码表述的逻辑来看,直觉上应该是会创建多个同一类型的对象实例,但实际上最终结果却不是这样,依赖注入的都是同一个 Singleton 的对象实例,那这是如何做到的?
     一开始以为 Spring 框架会通过解析 JavaConfig 的代码结构,然后通过解析器转换加上反射等方式完成这一目的,但实际上 Spring 框架的设计和实现者采用了另一种更通用的方式,这在 Spring 的参考文档中有说明。即通过拦截配置类的方法调用来避免多次初始化同一类型对象的问题,一旦拥有拦截逻辑的子类发现当前方法没有对应的类型实例时才会去请求父类的同一方法来初始化对象实例,否则直接返回之前的对象实例。
     所以,原来 Spring IoC 容器中有的特性(features)在 JavaConfig 中都可以表述,只是换了一种形式而已,而且,通过声明相应的 Java Annotation 反而“内聚”一处,变得更加简洁明了了。

那些高曝光率的 Annotation

     至于 @Configuration,我想前面已经提及过了,这里不再赘述,下面我们看几个其他比较常见的 Annotation,便于为后面更好地理解 SpringBoot 框架的奥秘做准备。

1. @ComponentScan

       @ComponentScan 对应 XML 配置形式中的 <context:component-scan> 元素,用于配合一些元信息 Java Annotation,比如 @Component 和 @Repository 等,将标注了这些元信息 Annotation 的 bean 定义类批量采集到 Spring 的 IoC 容器中。
我们可以通过 basePackages 等属性来细粒度地定制 @ComponentScan 自动扫描的范围,如果不指定,则默认 Spring 框架实现会从声明 @ComponentScan 所在类的 package 进行扫描。
       @ComponentScan 是 SpringBoot 框架得以实现的一个关键组件,大家可以重点关注,我们后面还会遇到它。

2. @PropertySource 与 @PropertySources

@PropertySource 用于从某些地方加载 *.properties 文件内容,并将其中的属性加载到 IoC 容器中,便于填充一些 bean 定义属性的占位符(placeholder),当然,这需要 PropertySourcesPlaceholderConfigurer 的配合。
如果我们使用 Java 8 或者更高版本开发,那么,我们可以并行声明多个

@Setter
@Getter
@ToString
@AllArgsConstructor
public class DataSource {

    private String username;
    private String password;
    private String url;
}
db.username=root
db.password=123456
db.url=jdbc:mysql://127.0.0.1:3306/test

@Configuration
@PropertySource("classpath:db.properties")
public class AppConfig {
    // @Value相当于 <property name="username" value="${db.username}"/>
    @Value("${db.username}")
    private String username;
    @Value("${db.password}")
    private String password;
    @Value("${db.url}")
    private String url;

    // 该bean是为了解析@Value中SpringEL表达式
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public DataSource dataSource() {
        return new DataSource(username, password, url);
    }
}

  如果我们使用低于 Java 8 版本的 Java 开发 Spring 应用,又想声明多个 @PropertySource,则需要借助 @PropertySources 的帮助了,代码如下所示:

@PropertySources({ @PropertySource("classpath:1.properties"), @PropertySource("classpath:2.properties"), ...})
public class XConfiguration{
    ...
}

3. @Import 与 @ImportResource

  在 XML 形式的配置中,我们通过 <import resource="XXX.xml"/> 的形式将多个分开的容器配置合到一个配置中,在 JavaConfig 形式的配置中,我们则使用 @Import 这个 Annotation 完成同样目的:

public class Test1 {
	public void printMsg(String msg) {
		System.out.println("test1 : " + msg);
	}
}
public class Test2 {
	public void printMsg(String msg) {
		System.out.println("test2 : " + msg);
	}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Test1Config {
	@Bean(name = "test1")
	public Test1 test1() {
		return new Test1();
	}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Test2Config {
	@Bean(name = "test2")
	public Test2 test2() {
		return new Test2();
	}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({ Test1Config.class, Test2Config.class })
public class AppConfig {

}
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Test1 test1 = (Test1) context.getBean("test1");
test1.printMsg("Hello test1");
Test2 test2 = (Test2) context.getBean("test2");
test2.printMsg("Hello test2");

    @Import 只负责引入 JavaConfig 形式定义的 IoC 容器配置,如果有一些遗留的配置或者遗留系统需要以 XML 形式来配置(比如 dubbo 框架),我们依然可以通过 @ImportResource 将它们一起合并到当前 JavaConfig 配置的容器中。

4.解析pom文件

  4.1.父项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

上面的配置是我们自己项目需要依赖的父项目【spring‐boot‐starter‐parent】

   我们现在新建的SpringBoot项目是【spring‐boot‐starter‐parent】项目下的一个子项目,我们的SpringBoot项目继承了【spring‐boot‐starter‐parent】父项目。

【spring‐boot‐starter‐parent】父项目继承了【spring-boot-dependencies】

spring‐boot‐starter‐parent-2.4.0.pom
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.4.0</version>
</parent>

【spring‐boot‐starter‐parent】父项目是【spring-boot-dependencies】的子项目

spring-boot-dependencies-2.4.0.pom
<properties>
  <activemq.version>5.16.0</activemq.version>
  <antlr2.version>2.7.7</antlr2.version>
  <appengine-sdk.version>1.9.83</appengine-sdk.version>
  <artemis.version>2.15.0</artemis.version>
  <aspectj.version>1.9.6</aspectj.version>
  <assertj.version>3.18.1</assertj.version>
  <atomikos.version>4.0.6</atomikos.version>
  <awaitility.version>4.0.3</awaitility.version>
  <bitronix.version>2.1.4</bitronix.version>
......
</properties>

上面的<properties>元素中配置的是我们所创建的项目的所有依赖包版本

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-amqp</artifactId>
      <version>${activemq.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-blueprint</artifactId>
      <version>${activemq.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-broker</artifactId>
      <version>${activemq.version}</version>
    </dependency>
.......
</dependencies>
</dependencyManagement>

   上面的<dependencies>元素中配置的是我们所创建的项目的所有依赖包的导入

    这个【spring‐boot‐dependencies】项目实际是用来真正管理Spring Boot应用里面的所有依赖包。

    有了【spring‐boot‐dependencies】项目以后我们新建的SpringBoot项目所需要的依赖包导入就不要在再配置版本和<dependencies>元素导入依赖,从【spring‐boot‐dependencies】项目中继承就可以了。

4.2SpringBoot启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<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>
    <scope>test</scope>
</dependency>

  命名:spring-boot-starter-xxxx  [SpingBoot的启动器]

spring-boot-starter:帮助我们导入springboot基础依赖包

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖包。

spring-boot-starter-test:帮我们导入了单元测试模块正常运行所依赖包。

    Spring Boot将所有的功能的依赖包都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter 那么实现相关功能的所有依赖都会自动导入进来,且没有版本冲突。要用什么功能就导入什么场景的启动器就可以了 。

基本的启动器

Spring Boot应用启动器基本的一共有44种,具体如下:

1)spring-boot-starter:这是Spring Boot的核心启动器,包含了自动配置、日志和YAML。

2)spring-boot-starter-actuator:帮助监控和管理应用。

3)spring-boot-starter-amqp:通过spring-rabbit来支持AMQP协议(Advanced Message Queuing Protocol)。

4)spring-boot-starter-aop:支持面向方面的编程即AOP,包括spring-aop和AspectJ。

5)spring-boot-starter-artemis:通过Apache Artemis支持JMS的API(Java Message Service API)。

6)spring-boot-starter-batch:支持Spring Batch,包括HSQLDB数据库。

7)spring-boot-starter-cache:支持Spring的Cache抽象。

8)spring-boot-starter-cloud-connectors:支持Spring Cloud Connectors,简化了在像Cloud Foundry或Heroku这样的云平台上连接服务。

9)spring-boot-starter-data-elasticsearch:支持ElasticSearch搜索和分析引擎,包括spring-data-elasticsearch。

10)spring-boot-starter-data-gemfire:支持GemFire分布式数据存储,包括spring-data-gemfire。

11)spring-boot-starter-data-jpa:支持JPA(Java Persistence API),包括spring-data-jpa、spring-orm、Hibernate。

12)spring-boot-starter-data-mongodb:支持MongoDB数据,包括spring-data-mongodb。

13)spring-boot-starter-data-rest:通过spring-data-rest-webmvc,支持通过REST暴露Spring Data数据仓库。

14)spring-boot-starter-data-solr:支持Apache Solr搜索平台,包括spring-data-solr。

15)spring-boot-starter-freemarker:支持FreeMarker模板引擎。

16)spring-boot-starter-groovy-templates:支持Groovy模板引擎。

17)spring-boot-starter-hateoas:通过spring-hateoas支持基于HATEOAS的RESTful Web服务。

18)spring-boot-starter-hornetq:通过HornetQ支持JMS。

19)spring-boot-starter-integration:支持通用的spring-integration模块。

20)spring-boot-starter-jdbc:支持JDBC数据库。

21)spring-boot-starter-jersey:支持Jersey RESTful Web服务框架。

22)spring-boot-starter-jta-atomikos:通过Atomikos支持JTA分布式事务处理。

23)spring-boot-starter-jta-bitronix:通过Bitronix支持JTA分布式事务处理。

24)spring-boot-starter-mail:支持javax.mail模块。

25)spring-boot-starter-mobile:支持spring-mobile。

26)spring-boot-starter-mustache:支持Mustache模板引擎。

27)spring-boot-starter-redis:支持Redis键值存储数据库,包括spring-redis。

28)spring-boot-starter-security:支持spring-security。

29)spring-boot-starter-social-facebook:支持spring-social-facebook

30)spring-boot-starter-social-linkedin:支持pring-social-linkedin

31)spring-boot-starter-social-twitter:支持pring-social-twitter

32)spring-boot-starter-test:支持常规的测试依赖,包括JUnit、Hamcrest、Mockito以及spring-test模块。

33)spring-boot-starter-thymeleaf:支持Thymeleaf模板引擎,包括与Spring的集成。

34)spring-boot-starter-velocity:支持Velocity模板引擎。

35)spring-boot-starter-web:支持全栈式Web开发,包括Tomcat和spring-webmvc。

36)spring-boot-starter-websocket:支持WebSocket开发。

37)spring-boot-starter-ws:支持Spring Web Services。

Spring Boot应用启动器面向生产环境的还有2种,具体如下:

1)spring-boot-starter-actuator:增加了面向产品上线相关的功能,比如测量和监控。

2)spring-boot-starter-remote-shell:增加了远程ssh shell的支持。

最后,Spring Boot应用启动器还有一些替换技术的启动器,具体如下:

1)spring-boot-starter-jetty:引入了Jetty HTTP引擎(用于替换Tomcat)。

2)spring-boot-starter-log4j:支持Log4J日志框架。

3)spring-boot-starter-logging:引入了Spring Boot默认的日志框架Logback。

4)spring-boot-starter-tomcat:引入了Spring Boot默认的HTTP引擎Tomcat。

5)spring-boot-starter-undertow:引入了Undertow HTTP引擎(用于替换Tomcat)。

5.SpringBoot的主类

package com.wangxing.springboot.springbootdemo1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.wangxing.springboot")
public class Springbootdemo1Application {
    public static void main(String[] args) {
        SpringApplication.run(Springbootdemo1Application.class, args);
    }
}

之所以说Springbootdemo1Application 是主类是因为它里面包含了主方法

 public static void main(String[] args) {}

在这个主方法中有

SpringApplication.run(Springbootdemo1Application.class, args);

   SpringApplication 将一个典型的 Spring 应用启动的流程“模板化”(这里是动词),在没有特殊需求的情况下,默认模板化后的执行流程就可以满足需求了但有特殊需求也没关系,SpringApplication 在合适的流程结点开放了一系列不同类型的扩展点,我们可以通过这些扩展点对 SpringBoot 程序的启动和关闭过程进行扩展。

通过SpringApplication设置修改启动图标

1.在resources文件夹中创建banner.txt

banner.txt中的内容

'##::::'##:'########:'##:::::::'##::::::::'#######::
 ##:::: ##: ##.....:: ##::::::: ##:::::::'##.... ##:
 ##:::: ##: ##::::::: ##::::::: ##::::::: ##:::: ##:
 #########: ######::: ##::::::: ##::::::: ##:::: ##:
 ##.... ##: ##...:::: ##::::::: ##::::::: ##:::: ##:
 ##:::: ##: ##::::::: ##::::::: ##::::::: ##:::: ##:
 ##:::: ##: ########: ########: ########:. #######::
..:::::..::........::........::........:::.......:::

2.在主类中通过SpringApplication来设置启动图标

package com.wangxing.springboot.springbootdemo1;

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;

import java.io.PrintStream;

@SpringBootApplication
@ComponentScan(basePackages = "com.wangxing.springboot")
public class Springbootdemo1Application {
    public static void main(String[] args) {
        SpringApplication bootstrap = new SpringApplication(Springbootdemo1Application.class);
        bootstrap.setBannerMode(Banner.Mode.CONSOLE);
        bootstrap.run(args);
    }
}

SpringApplication的run方法的执行流程

SpringApplication 的 run 方法的实现是我们本次运行的主要线路,该方法的主要流程大体可以归纳如下:
1)如果我们使用的是 SpringApplication 的静态 run 方法,那么,这个方法里面首先需要创建一个 SpringApplication 对象实例,然后调用这个创建好的 SpringApplication 的实例 run方 法。在 SpringApplication 实例初始化的时候,它会提前做几件事情:
根据 classpath 里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为 Web 应用使用的 ApplicationContext 类型,还是应该创建一个标准 Standalone 应用使用的 ApplicationContext 类型。


使用 SpringFactoriesLoader 在应用的 classpath 中查找并加载所有可用的 ApplicationContextInitializer。


使用 SpringFactoriesLoader 在应用的 classpath 中查找并加载所有可用的 ApplicationListener。
推断并设置 main 方法的定义类。

从Spring工厂获取引导注册表初始化器

推断并设置 main 方法的定义类。


2)SpringApplication 实例初始化完成并且完成设置后,就开始执行 run 方法的逻辑 了,

方法执行伊始,首先遍历执行所有通过 SpringFactoriesLoader 可以查找到并加载的 SpringApplicationRunListener,调用它们的 started() 方法,告诉这些 SpringApplicationRunListener,“嘿,SpringBoot 应用要开始执行咯!”。


3)创建并配置当前 SpringBoot 应用将要使用的 Environment(包括配置要使用的 PropertySource 以及 Profile)。


4)遍历调用所有 SpringApplicationRunListener 的 environmentPrepared()的方法,告诉它们:“当前 SpringBoot 应用使用的 Environment 准备好咯!”。


5)如果 SpringApplication的showBanner 属性被设置为 true,则打印 banner(SpringBoot 1.3.x版本,这里应该是基于 Banner.Mode 决定 banner 的打印行为)。这一步的逻辑其实可以不关心,我认为唯一的用途就是“好玩”(Just For Fun)。


6)根据用户是否明确设置了applicationContextClass 类型以及初始化阶段的推断结果,决定该为当前 SpringBoot 应用创建什么类型的 ApplicationContext 并创建完成,然后根据条件决定是否添加 ShutdownHook,决定是否使用自定义的 BeanNameGenerator,决定是否使用自定义的 ResourceLoader,当然,最重要的,将之前准备好的 Environment 设置给创建好的 ApplicationContext 使用。

停止计时


7)ApplicationContext 创建好之后,SpringApplication 会再次借助 Spring-FactoriesLoader,查找并加载 classpath 中所有可用的 ApplicationContext-Initializer,然后遍历调用这些 ApplicationContextInitializer 的 initialize(applicationContext)方法来对已经创建好的 ApplicationContext 进行进一步的处理。


8)遍历调用所有 SpringApplicationRunListener 的 contextPrepared()方法,通知它们:“SpringBoot 应用使用的 ApplicationContext 准备好啦!”


9)最核心的一步,将之前通过 @EnableAutoConfiguration 获取的所有配置以及其他形式的 IoC 容器配置加载到已经准备完毕的 ApplicationContext。


10)遍历调用所有 SpringApplicationRunListener 的 contextLoaded() 方法,告知所有 SpringApplicationRunListener,ApplicationContext "装填完毕"!


11)调用 ApplicationContext 的 refresh() 方法,完成 IoC 容器可用的最后一道工序。


12)查找当前 ApplicationContext 中是否注册有 CommandLineRunner,如果有,则遍历执行它们。


13)正常情况下,遍历执行 SpringApplicationRunListener 的 finished() 方法,告知它们:“搞定!”。(如果整个过程出现异常,则依然调用所有 SpringApplicationRunListener 的 finished() 方法,只不过这种情况下会将异常信息一并传入处理)。
至此,一个完整的 SpringBoot 应用启动完毕!


整个过程看起来冗长无比,但其实很多都是一些事件通知的扩展点,如果我们将这些逻辑暂时忽略,那么,其实整个 SpringBoot 应用启动的逻辑就可以压缩到极其精简的几步,如图 1 所示。

前后对比我们就可以发现,其实 SpringApplication 提供的这些各类扩展点近乎“喧宾夺主”,占据了一个 Spring 应用启动逻辑的大部分“江山”,除了初始化并准备好ApplicationContext,剩下的大部分工作都是通过这些扩展点完成的,所以,我们接下来对各类扩展点进行逐一剖析。

1SpringApplication 的静态 run 方法运行 SpringApplication 的静态 run 方法,那么,这个方法里面首先需要创建一个 SpringApplication 对象实例,收集各种条件和回调接口,创建ApplicationContextInitializer 、ApplicationContextListener,创建SpringApplicationRunListeners调用它的started()方法,告诉SpringBoot 应用要开始执行,创建并配置当前 SpringBoot 应用将要使用的 Environment(包括配置要使用的 PropertySource 以及 Profile),利用SpringApplicationRunListener调用environmentPrepared()的方法,告诉SpringBoot 应用使用的 Environment 准备好,创建并初始化ApplicationContext,利用 SpringApplicationRunListener的contextPrepared()方法,通知SpringBoot 应用使用的 ApplicationContext 准备好,将之前通过 @EnableAutoConfiguration 获取的所有配置以及其他形式的 IoC 容器配置加载到已经准备完毕的 ApplicationContext,利用SpringApplicationRunListener 的 contextLoaded() 方法,告知所有 SpringApplicationRunListener,ApplicationContext "装填完毕",调用 ApplicationContext 的 refresh() 方法,一切准备就绪,当前 ApplicationContext 中是否注册有 CommandLineRunner,如果有,则遍历执行它们。遍历执行 SpringApplicationRunListener 的 finished() 方法,至此,一个完整的 SpringBoot 应用启动完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值