springboot listener_SpringBoot综述

直接切入正题,本文适合用过了解过相关Spring,SpringBoot的童靴

SpringBoot提供了三大特性:

  • 组件自动装配:Web MVC,Web Flux,JDBC等

  • 嵌入式Web容器:Tomcat,Jetty以及Undertow

  • 生产准备特性:指标,健康检查,外部化配置(不用写代码来调节用户的行为如容器的端口server:8081)等

组件自动装配

概念

SpringBoot中默认没有激活①,激活后同时需要相应的配置来进行映射②,该文件即可以是框架实现也可以用户自定义实现,最后他的实现的文件③

    ①激活:@EnableAutoConfiguration

    ②配置:/META-INF/spring.factories  相对于ClassPath的目录(META-INF指一个源信息目录(META为源的意思,factoriesactories类似于工厂的机制,即key,value的形式))

    ③实现:XXXAutoConfiguration   (如JDBCAutoConfiguration等等)

样例

https://start.spring.io/   来创建一个工程

①在SpringBoot启动项中我们只能看到@SpringBootApplication,我们进去一探究竟,这里使用了模式注解后面会进行介绍

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

点进@SpringBootApplication

e2b121fa37bb8974c162f34763921fa0.png

②③我们搜索下spring.factories

1ce9ca8e8c65b89a5c678730593c4c00.png

    可以看到springBoot中各种模块的装配,各个模块的value命名规则相同

ae7298993ea390584c3aee63e9bef83a.png

    spring启动的时候会读取配置文件装配上各个bean,比如WebMvcAutoConfiguration,可以看到因为没有引入依赖这个,所以这个工程不会被装配起来(需要引入starter包)。所以官网上建立的工程直接启动的时候就会直接结束了因为不是Web工程

bf77c2a356d63ec990e645c4c0839cd4.png

嵌入式Web容器

Web Servlet :Tomcat,Jetty和Undertow    Servlet容器

Web Reactive:Netty Web Server              Reactive容器

在SpringBoot编程中,两种容器的选择其实没有太大的区别

生产准备特性

    主要为一些功能性的特性。WebFlux,WebMVC,JDBC都是为开发做准备的,为生产做准备的如下:

  • 指标:/actuator/metrics     监控和管理应用的一些特性如metrics信息(如CPU,内存,磁盘利用率)

  • 健康检查:/actuator/health   如磁盘DB等的一些检查

  • 外部化配置:/actuator/configprops     通过修改配置文件来改变应用的行为,这个有点像实际项目中,很多参数调节为可配的(如yaml,properties文件里的参数,通过读取文件内容动态修改程序的规则),SpringBoot该功能源于Spring Framework,只是名字改了下

--------------------------------------------------------------------------

接下来我们来讨论下SpringBoot的Web应用

    传统的Servlet的应用,首先是一些相关的组件,然后如何将组件注册进来,在SpringBoot中我们允许把Servlet变为一个bean注入进来

  • Servlet组件:Servlet,Filter,Listener(事件监听者模式的实现)

  • Servlet注册:Servlet注解(Servlet3.0提供的特性),Spring Bean,RegistrationBean

  • 异步非阻塞:异步Servlet(Servlet3.0提供的特性),非阻塞Servlet(Servlet3.1提供的特性)

传统的Servlet的应用

传统Servlet应用需要引入依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

注:SpringBoot的自动装配是以Spring-Starter的方式来进行的,其中都为org.springframework.boot

    我们引入进包后,可以发现依赖中有子依赖,加入web后可以看到装配的bean可用了

138db85e7029d97027d329a9259bbdf3.png

a2de0a5cf2491048acfc62629c81a56f.png

    因为当你的依赖进来时,ClassPath上会有相应的类,条件满足自动装配,启动服务,我们也会看到Tomcat相关日志,这也与上面红色表示中引入Tomcat包有关联

2020-06-13 16:41:57.244  INFO 158980 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-06-13 16:41:57.378  INFO 158980 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2020-06-13 16:41:57.427  INFO 158980 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-06-13 16:41:57.430  INFO 158980 --- [           main] c.e.I.ImoocSpringProjectApplication      : Started ImoocSpringProjectApplication in 2.039 seconds (JVM running for 2.43)

Servlet注册

我们在SpringBoot中使用传统Servlet定义方式,主要分三个步骤

  1. 实现:实现类为MyServlet,需要继承HttpServlet,并覆盖doGet方法。且Servlet3.0需要加上@WebServlet注解来进行导入

  2. URL映射:@WebServlet中的urlPatterns参数 

  3. 注册:@ServletComponentScan,basePackages填写类的package信息

@WebServlet(urlPatterns = "/test")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("Hello World");
    }
}
@SpringBootApplication
@ServletComponentScan(basePackages = "com.example.ImoocSpringProject.web.servlet")
public class ImoocApplication {
    public static void main(String[] args) {
        SpringApplication.run(ImoocApplication.class, args);
    }
}

前端请求

0c2c484b5c565f2ac48fe501230cc252.png

异步非阻塞

异步Servlet

注意事项点:

(1)使用javax.servlet.ServletRequest#startAsync()

    javax.servlet.AsyncContext

(2)@WebServlet中需要标注asyncSupported参数才可支持异步,否则前端报错

(3)在获取异步上下文asyncContext后需要告诉他结束否则前端超时

@WebServlet(urlPatterns = "/test",asyncSupported = true)
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        AsyncContext asyncContext=req.startAsync();

        asyncContext.start(()->{
            try {
                resp.getWriter().println("Hello World");

                //触发完成,否则前端访问不成功会超时
                asyncContext.complete();
            } catch (IOException e) {
                e.printStackTrace();
                //增加日志说明
            }
        });
    }
}

其他不变运行结果相同

--------------------------------------------------------------------------

接下来我们来讨论下SpringBootWeb应用下的MVC

SpringWebMVC应用

  • Web MVC视图:模板引擎(如Thymeleaf),内容协商,异常处理(SpringBoot中的异常与Spring有所区别)

  • Web MVC REST:以json或xml为例下的资源服务(rest操作符如get/post请求下后面问题),资源跨域,服务发现等

WebMVC视图

涉及两个接口View和ViewResolver

    ViewResolver意思为视图处理器,处理器有一个处理方法resolveViewName,入参如viewName视图名称和local位置。

    返回值为View视图,而作为视图只关心它的渲染render,渲染则需要上下文变量Map model,入参request,出参则为输出的内容response,具体实现还是由render去实现

public interface ViewResolver {
    @Nullable
    View resolveViewName(String viewName, Locale locale) throws Exception;

}
public interface View {
        ...
    void render(@Nullable Map model, HttpServletRequest request, HttpServletResponse response)throws Exception;

}

    每一种模板引擎(Thymeleaf,Freemarker,JSP),对应不同的View和ViewResolver实现

    当一个应用中有多个模板引擎,这时就会涉及内容协商(ContentNegotiationConfigurer,ContentNegotiationStrategy,ContentNegotiatingViewResolver),内容协商会帮你选择最优的模板引擎进行渲染

    处理中的异常会用

  • @ExceptionHandler:(如SpringBoot中会使用HandlerExceptionResolver来处理异常功能,其中该注解是由其子类ExceptionHandlerExceptionResolver来实现的)

  • BasicErrorController:(如页面上的404返回就是该类参与)

cbd4b638e039d67361671be701aafcfd.png

Web MVC REST

首先是资源服务的处理@RequestMapping,@ResponseBody,@RequestBody

@RequestMapping在spring4.3之后又有了相应专门的拓展

d90555982e9809c769c942086417f773.png


其次是资源跨域

两种方案@CrossOrigin,WebMvcConfurer#addCorsMappings

SpringBoot重拾来自Spring Framework方法

最后服务发现

如使用IEDA中启动SpringBoot项目可以搜索“Mapped”,可以发现相应url映射,即服务的发现mapping

--------------------------------------------------------------------------

接下来我们来讨论MVC下的核心架构

(1)DispatcherServlet(它会把不同的请求转发到对应的controller中),(2)HandlerMapping(与controller中的映射即通过HandlerMapping,hander即方法,mapping即方法上唯一的url映射),

(3)HandlerAdapter(用来转换,即将上面方法抽象的东西,转化为具体内部实现来进行映射)

(4)ViewResolver(处理完后返回model-and-View的东西,给ViewResolver处理)

最后生成视图或者rest应用第四部后面会发生变化如返回json

--------------------------------------------------------------------------

接下来我们来讨论Spring Web Flux 应用

这个特性是Spring5开始支持,是对Servlet的一个补充,从传统同步阻塞式编程变为异步非阻塞。

这里会涉及到一些基础:

  • Reactor基础:java Lambda,Mono,Flux

  • Web Flux核心:Web MVC注解(可以与其兼容如@Controller,@RequestMapping等),函数式声明(用condition进行判断丰富拓展),异步非阻塞(Servlet3.1+,提高系统的吞吐量)

  • 使用场景:页面渲染和REST应用

这里我们给出一个老外测试的性能案例

https://blog.ippon.tech/spring-5-webflux-performance-tests/

691d009096406d09d62fa1e81a193911.png

Reactive并没有提升多大性能,因为Reactive提升系统的吞吐量,不代表快,后面会介绍。

实践

想要使用WebFlux等,你可能需要切换Web容器,自定义Reactive Web Server等,我们从基础开始

(1)Tomcat→Jetty

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-tomcatartifactId>
                exclusion>
            exclusions>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jettyartifactId>
        dependency>

启动Application

34bb27607f73ce7fa73f4412b765a64d.png

(2)Servlet→WebFlux

需要去掉之前的web-starter,添加webflux-starter

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webfluxartifactId>
        dependency>

--------------------------------------------------------------------------

接下来我们来讨论数据相关的特性

关系型数据

  • JDBC:数据源,JDBCTemplate,自动装配

  • JPA(java持久成api):实体映射关系,实体操作,自动装配

  • 事务:Spring事务抽象,JDBC事务处理,自动装配

JDBC

依赖也是starter

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jdbcartifactId>
        dependency>

    jdbc包导入注意,在spring2.0之后jdbc会使用性能非常好的连接池HikariCP,大家可以感兴趣了解下

ff3d925296a7d9f39e07ee93fd0054e0.png

数据源接口是java中特性  javax.sql.DataSource,JdbcTemplate其实是jdbc中模板的实现,我们以JdbcTemplate的自动装配为例:

@ConditionalOnClass为前提条件,因为JdbcTemplate依赖于DataSource所以看源码,我们会发现@AutoConfigureAfter,在datasource注入之后

c8b9a2af37e0e8af5a3caed00e174b14.png

    结合之前所说在spring.factories中会存在相应的AutoConfiguration

47598d78aacbe822c566134444e1d71b.png

    启动项目,会发现一些错误,当引入该模块你需要连接数据库,比如它说的embedded database嵌入式数据库放在classpath下面;或者传统Jdbc的方式

1d07a6ee5167617e425816725e3d8f97.png

JPA

依赖中jpa与jdbc不冲突,因为它需要jdbc的dataSource(dataSource会在DataSourceAutoConfiguration上自动装配,然后产生数据库连接池,然后保存,此阶段jpa也是需要的)

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-jpaartifactId>
        dependency>

    jpa中的一些实现如Hibernate,因为jpa只是一套规范标准,具体实现提供方如Hibernate,同时你也能看到间接引用了jdbc,此时会重复

5f2c7aa344e19a5ded8035d985cf989a.png

实体映射关系中与数据库相似,数据库通常是外界或者表的关系进行关联,在JPA中叫做实体,其操作通过javax.persistence.EntityManager进行实现,如实现基本的一些增删改查的一些接口实现

public interface EntityManager {
    void persist(Object var1); //类似于存

     T merge(T var1); //类似于更新void remove(Object var1);  //类似于删除 T find(Class var1, Object var2); //类似于查找,var1即bean,var2即查找的主键或者某个字段 T find(Class var1, Object var2, Map<String, Object> var3); T find(Class var1, Object var2, LockModeType var3); T find(Class var1, Object var2, LockModeType var3, Map<String, Object> var4); T getReference(Class var1, Object var2);
    ...
}

自动装配则使用HibernateJpaAutoConfiguration,依赖DataSourceAutoConfiguration

536d049b61999abd4f5468947c1b174c.png

事务

依赖

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-txartifactId>
        dependency>

Spring事务的抽象实现接口为PlatformTransactionManager,该接口主要提供两种事务的抽象,第一个Jta分布式事务,DataSource数据库事务

a092375929466010a3b6bed377bf1488.png

自动装配是在TransactionAutoConfiguration中。同时他需要类@ConditionalOnClass(PlatformTransactionManager.class),该类在我们上面引用的tx jar包中

db7b34b511098cf31a78fe4aea118606.png

--------------------------------------------------------------------------

接下来我们来讨SpringBoot论拓展功能

SpringBoot应用中,从下面三个点分析

  • SpringApplication:失败分析,应用特性,事件监听(重点)

  • SpringBoot配置:外部化配置(主要依赖Spring Framework中api),Profile,配置属性

  • SpringBoot Starter:Starter开发

    这里提一下SpringApplication中有一种Fluent API的特性,在SpringBoot启动项中我们使用Builder模式进行重建。

@SpringBootApplication(scanBasePackages = "com.example")
public class DemoApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(DemoApplication.class)
                .run(args);
        //SpringApplication.run(DemoApplication.class, args);
    }
}

    Fluent API即当我们不想要web工程时可以.web()进行选择,如不使用NONE,REACTIVE模式等。需要什么则进行.添加

5c260bef6e75b678b14273bc2574755d.png

    同时SpringBoot的配置属性中外部化配置在2.0中变为使用ConfigurationProperty,在传统的key,value下引入了新的配置属性origin,即属性的来源,用来跟踪配置从哪里来,因为SpringBoot中配置非常多,为了解决配置是从具体什么地方来的

762589ebac8c2da67d0b5b20eb69c87e.png

@Profile即代表条件的意思,能力较弱,不如使用@Conditional

805c6e00d0fb361347d884d42ba306a4.png

配置属性PropertySources,是Spring能力;会有两种实现方式接口和注解

a74886587716d6700cbfa5f296537541.png

--------------------------------------------------------------------------

接下来我们来讨SpringBoot运维管理

SpringBoot Actuator

  • 端点的方式:各类Web EndPoints和JMX EndPoints

  • 健康检查:Health,HealthIndicator

  • 指标:内建Metrics,自定义Metrics

需要引入依赖

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>

具体参考SpringBoot文档

后记:后面会分别对这些中重点的部分进行详细的探讨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值