开发者

SpringBoot的pom文件、容器、组件使用及说明

开发者 https://www.devze.com 2025-11-15 10:26 出处:网络 作者: JunSouth
目录一、pom文件、配置文件1、pom文件2、配置文件二、Spring的流程1、Spring的启动2、Spring中bean的生命周期三、内置容器1、Tomcat(默认)1.Tomcat组成、架构2.Tomcat性能调优3.Tomcat热加载实4.Tomcat热部署2、Jett
目录
  • 一、pom文件、配置文件
    • 1、pom文件
    • 2、配置文件
  • 二、Spring的流程
    • 1、Spring的启动
    • 2、Spring中bean的生命周期
  • 三、内置容器
    • 1、Tomcat(默认)
      • 1.Tomcat组成、架构
      • 2.Tomcat性能调优
      • 3.Tomcat热加载实
      • 4.Tomcat热部署
    • 2、Jetty
      • 1.替换默认的Tomcat容器
      • 2.重要参数
    • 3、Undertow
      • 1.替换默认的Tomcat容器
      • 2.重要参数
    • 4、Netty
      • 1、SpringBoot整合Netty(服务端)
      • 2、Netty客户端
  • 三、重要组件
    • 总结

      一、pom文件、配置文件

      1、pom文件

      <?XML version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          
          <!-- pom模型版本 -->
          <modelVersion>4.0.0</modelVersion>
          
          <!-- 项目信息 -->
          <groupId>demo</groupId><!-- 项目唯一标识 -->
          <artifactId>springboot</artifactId><!-- 项目名 -->
          <version>0.0.1-SNAPSHOT</version><!-- 版本 -->
          <packaging>jar</packaging><!-- 打包方式 (pom,war,jar) -->
       
         编程客栈 <name>springboot</name><!-- 项目的名称, Maven 产生的文档用 -->
          <description>Demo project for Spring Boot</description><!-- 项目的描述, Maven 产生的文档用 -->
       
          <!-- 父级项目 -->
      	<parent> 
              <artifactId>spring-boot-starter-parent</artifactId>  <!-- 被继承的父项目的构件标识符 --> 
              <groupId>org.springframework.boot</groupId>  <!-- 被继承的父项目的全球唯一标识符 -->
              <version>1.5.7.RELEASE</version>  <!-- 被继承的父项目的版本 --> 
              <!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是../pom.xml。
                   Maven首先在构建当前项目的地方寻找父项目的pom,其次在文件系统的这个位置(relativePath位置),
                   然后在本地仓库,最后在远程仓库寻找父项目的pom。 --> 
              <relativePath/> <!-- lookup parent from repository -->
          </parent> 
      	
      	<!-- 模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径 --> 
          <modules> 
              <!-- 子项目相对路径 --> 
              <module></module> 
          </modules> 
      	
          <!-- 属性设置 -->
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 编译字符编码为utf-8 -->
              <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- 输出字符编码为UTF-8  -->
              <Java.version>1.8</java.version><!-- jdK版本 -->
          </properties>
          
          <!-- 依赖关系 -->
          <dependencies>
              <!-- 测试 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
              </dependency>
              <!-- mysql(数据库) -->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <scope>runtime</scope>
              </dependency>
          </dependencies>
          <!-- 编译 -->
          <build>
              <!-- 插件 -->
              <plugins>
                  <!-- maven插件 -->
                  <plugin>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-maven-plugin</artifactId>
                  </plugin>
              </plugins>
          </build>
      </project>

      2、配置文件

      SpringBoot 支持以下几种类型的配置文件:

      • application.properties:基于属性键值对的配置文件,使用简单的 key=value 格式,可读性较高。
      • application.yml:基于 YAML 格式的配置文件,使用缩进和冒号表示属性的层次结构,可读性更好。
      • application.yaml:与 application.yml 相同,只是文件扩展名不同。

      优先级从高到低

      properties -> yml -> yaml

      bootstrap.yml配置文件

      在 SpringCloud 的项目中常用到 bootstrap.yml配置文件,用于应用程序上下文的引导阶段,在 application.yml 之前加载。

      二、Spring的流程

      1、Spring的启动

      SpringBoot的pom文件、容器、组件使用及说明

      2、Spring中bean的生命周期

      (1).Spring对bean进行实例化;

      (2).Spring将值和bean的引用注入到bean对应的属性中;

      (3).bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;

      (4).bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;

      (5).bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;

      (6).bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法;

      (7).bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,

      (8).bean使用initmethod声明了初始化方法,该方法也会被调用;

      (9).bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;

      (10).bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;

      (11).bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

      三、内置容器

      SpringBoot提供了四种Web容器,分别为Tomcat,Jetty,Undertow,Netty。

      1、Tomcat(默认)

      Tomcat在8.0之前默认采⽤的I/O⽅式为BIO,之后改为NIO,适合处理少数非常繁忙的链接。

      SpringBoot的pom文件、容器、组件使用及说明

      1.Tomcat组成、架构

      (1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个 Connector(链接) 和一个 Container(容器);

      (2)Server 掌管着整个Tomcat的生死大权;

      (4)Service 是对外提供服务的;

      (5)Connector 用于接受请求并将请求封装成Request和Response来具体处理;

      (6)Container 用于封装和管理Servlet,以及具体处理request请求;

      SpringBoot的pom文件、容器、组件使用及说明

      2.Tomcat性能调优

      • namePrefix: 线程前缀
      • maxThreads: 最大线程数,默认设置 200,一般建议在 500 ~ 1000,根据硬件设施和业务来判断
      • minSpareThreads: 核心线程数,默认设置 25
      • prestartminSpareThreads: 在 Tomcat 初始化的时候就初始化核心线程
      • maxQueueSize: 最大的等待队列数,超过则拒绝请求 ,默认 Integer.MAX_VALUE
      • maxIdleTime: 线程空闲时间,超过该时间,线程会被销毁,单位毫秒。

      3.Tomcat热加载实

      调用 Context 容器的 reload 方法,先stop Context容器,再start Context容器。具体的实现:

      1)停止和销毁 Context 容器及其所有子容器,子容器其实就是 Wrapper,也就是说 Wrapper 里面 Servlet 实例也被销毁了。

      2)停止和销毁 Context 容器关联的 Listener 和 Filter。

      3)停止和销毁 Context 下的 Pipeline 和各种 Valve。

      4)停止和销毁 Context 的类加载器,以及类加载器加载的类文件资源。

      5)启动 Context 容器,在这个过程中会重新创建前面四步被销毁的资源。

      • Context 容器对应一个类加载器,类加载器在销毁的过程中会把它加载的所有类也全部销毁。
      • Context 容器在启动过程中,会创建一个新的类加载器来加载新的类文件。

      4.Tomcat热部署

      热部署跟热加载的本质区别是,热部署会重新部署 Web 应用,原来的 Context 对象会整个被销毁掉,因此这个 Context 所关联的一切资源都会被销毁,包括 Session。

      Host 容器并没有在 backgroundProcess 方法中实现周期性检测的任务,而是通过监听器 HostConfig 来实现的(HostConfig#lifecycleEvent)

      HostConfig 会检查 webapps 目录下的所有 Web 应用:如果原来 Web 应用目录被删掉了,就把相应 Context 容器整个销毁掉。是否有新的 Web 应用目录放进来了,或者有新的 WAR 包放进来了,就部署相应的 Web 应用。

      因此 HostConfig 做的事情都是比较“宏观”的,它不会去检查具体类文件或者资源文件是否有变化,而是检查 Web 应用目录级别的变化。

      2、Jetty

      开源的webserver/servlet容器,是基于 NIO模型。

      通过Handler实现扩展简单。Jetty和Tomcat性能方面差异不大Jetty可以同时处理大量连接而且可以长时间保持连接适合于web聊天应用等

      SpringBoot的pom文件、容器、组件使用及说明

      1.替换默认的Tomcat容器

      <dependencies>
          <dependency>
              <groupid>org.springframework.boot</groupid>
              <artifactid>spring-boot-starter-web</artifactid>
              <exclusions>
                  <!-- 去除Tomcat容器 -->
                  <exclusion>
                      <groupid>org.springframework.boot</groupid>
                      <artifactid>spring-boot-starter-tomcat</artifactid>
                  </exclusion>
              </exclusions>
          </dependency>
          <!-- 增加Jetty容器 -->
          <dependency>
              <groupid>org.springframework.boot</groupid>
              <artifactid>spring-boot-starter-jetty</artifactid>
          </dependency>
      </dependencies>

      2.重要参数

      是否打开Jetty日志(默认关闭):server.jetty.Accesslog.enabled

      • 访问日志所在目录:server.jetty.http://www.devze.comaccesslog.dir
      • 最大线程数:server.jetty.threads.max
      • 最小线程数:server.jetty.threads.min
      • 最大队列容量:server.jetty.threads.max-queue-capacity
      • 线程最大空闲时间:server.jetty.threads.idle-timeout

      3、Undertow

      轻量级:Undertow 是非常小的,只有不到1MB。在内嵌模式下,运行时只占heap空间的4MB左右。

      支持 Servlet 3.1

      Web Socket:支持 Web Socket (包括jsR-356)

      长连接:默认情况下,Undertow 通过添加keep-alive 的response header来支持长连接。它通过重用连接信息(connection details)来改善长连接的性能。

      1.替换默认的Tomcat容器

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <exclusions>
            <!-- 去除 Tomcat 容器 -->
              <exclusion>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-tomcat</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
        <!-- 添加 Undertow 容器 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-undertow</artifactId>
      </dependency>

      2.重要参数

      # Undertow 日志存放目录
      server.undertow.accesslog.dir=
      # 是否启动日志
      server.undertow.accesslog.enabled=false
      # 日志格式
      server.undertow.accesslog.pattern=common
      # 日志文件名前缀
      server.undertow.accesslog.prefix=access_log
      # 日志文件名后缀
      server.undertow.accesslog.suffix=log
      # HTTP POST请求最大的大小
      server.undertow.max-http-post-size=0
      # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
      # 不要设置过大,如果过大,启动项目会报错:打开文件数过多
      server.undertow.io-threads=12
      # 阻塞任务线程池, 当执行类似servlet请求阻塞IO操作, undertow会从这个线程池中取得线程
      # 它的值设置取决于系统线程执行任务的阻塞系数,默认值是IO线程数*8
      server.undertow.worker-threads=20
      # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
      # 每块buffer的空间大小,越小的空间被利用越充分,不要设置太大,以免影响其他应用,合适即可
      server.undertow.buffer-size=1024
      # 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region
      server.undertow.buffers-per-region=1024
      # 是否分配的直接内存
      server.undertow.direct-buffers=true

      4、Netty

      1、SpringBoot整合Netty(服务端)

      1.配置
      <!-- netty -->
      <dependency>
          <groupId>io.netty</groupId>
          <artifactId>netty-all</artifactId>
          <version>4.1.36.Final</version>
      </dependency>
      # netty 配置
      netty:
        # boss线程数量
        boss: 4
        # worker线程数量
        worker: 2
        # 连接超时时间
        timeout: 6000
        # 服务器主端口
        port: 17000
        # 服务器备用端口
        portSalve: 18026
        # 服务器地址
        host: 127.0.0.1
      2.编写netty处理器
      /**
       * Socket拦截器,用于处理客户端的行为
       **/
      @Slf4j
      public class SocketHandler extends ChannelInboundHandlerAdapter {
          public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
      
          /**
           * 读取到客户端发来的消息
           */
          @Override
          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
              // 由于我们配置的是 字节数组 编解码器,所以这里取到的用户发来的数据是 byte数组
              byte[] data = (byte[]) msg;
              log.info("收到消息: " + new String(data));
              // 给其他人转发消息
              for (Channel client : clients) {
                  if (!client.equals(ctx.channel())) {
                      client.writeAndFlush(data);
                  }
              }
          }
      
          @Override
          public void handlerAdded(phpChannelHandlerContext ctx) throws Exception {
              log.info("新的客户端链接:" + ctx.channel().id().asShortText());
              clients.add(ctx.channel());
          }
      
          @Override
          public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
              clients.remove(ctx.channel());
          }
      
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
              cause.printStackTrace();
              ctx.channel().close();
              clients.remove(ctx.channel());
          }
      }
      3.编写netty初始化器
      /**
       * Socket 初始化器,每一个Channel进来都会调用这里的 InitChannel 方法
       **/
      @Component
      public class SocketInitializer extends ChannelInitializer<SocketChannel> {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
              ChannelPipeline pipeline = socketChannel.pipeline();
              // 添加对byte数组的编解码,netty提供了很多编解码器,你们可以根据需要选择
              pipeline.addLast(new ByteArrayDecoder());
              pipeline.addLast(new ByteArrayEncoder());
              // 添加上自己的处理器javascript
              pipeline.addLast(new SocketHandler());
          }
      }
      4.编写netty服务
      @Slf4j
      @Component
      public class SocketServer {
          @Resource
          private SocketInitializer socketInitializer;
      
          @Getter
          private ServerBootstrap serverBootstrap;
      
          /**
           * netty服务监听端口
           */
          @Value("${netty.port:17000}")
          private int port;
          /**
           * 主线程组数量
           */
          @Value("${netty.boss:4}")
          private int bossThread;
      
          /**
           * 启动netty服务器
           */
          public void start() {
              this.init();
              this.serverBootstrap.bind(this.port);
              log.info("Netty started on port: {} (TCP) with boss thread {}", this.port, this.bossThread);
          }
      
          /**
           * 初始化netty配置
           */
          private void init() {
              // 创建两个线程组,bossGroup为接收请求的线程组,一般1-2个就行
              NioEventLoopGroup bossGroup = new NioEventLoopGroup(this.bossThread);
              // 实际工作的线程组
              NioEventLoopGroup workerGroup = new NioEventLoopGroup();
              this.serverBootstrap = new ServerBootstrap();
              this.serverBootstrap.group(bossGroup, workerGroup) // 两个线程组加入进来
                      .channel(NIOServerSocketChannel.class)  // 配置为nio类型
                      .childHandler(this.socketInitializer); // 加入自己的初始化器
          }
      }
      5.启动netty
      /**
       * 监听Spring容器启动完成,完成后启动Netty服务器
       **/
      @Component
      public class NettyStartListener implements ApplicationRunner {
          @Resource
          private SocketServer socketServer;
      
          @Override
          public void run(ApplicationArguments args) throws Exception {
              this.socketServer.start();
          }
      }

      2、Netty客户端

      客户端用NIO来编写,在实际工作中客户端可能是 WebSocket、Socket,以 Socket 为例。

      1.编写客户端线程
      public class ClientThread implements Runnable{
      
          private final Selector selector;
      
          public ClientThread(Selector selector) {
              this.selector = selector;
          }
      
          @Override
          public void run() {
              try {
                  for (; ; ) {
                      int channels = selector.select();
                      if (channels == 0) {
                          continue;
                      }
                      Set<SelectionKey> selectionKeySet = selector.selectedKeys();
                      Iterator<SelectionKey> keyIterator = selectionKeySet.iterator();
                      while (keyIterator.hasNext()) {
                          SelectionKey selectionKey = keyIterator.next();
      
                          // 移除集合当前得selectionKey,避免重复处理
                          keyIterator.remove();
                          if (selectionKey.isReadable()) {
                              this.handleRead(selector, selectionKey);
                          }
                      }
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          // 处理可读状态
          private void handleRead(Selector selector, SelectionKey selectionKey) throws IOException {
              SocketChannel channel = (SocketChannel) sele编程客栈ctionKey.channel();
              ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
              StringBuilder message = new StringBuilder();
              if (channel.read(byteBuffer) > 0) {
                  byteBuffer.flip();
                  message.append(StandardCharsets.UTF_8.decode(byteBuffer));
              }
              // 再次注册到选择器上,继续监听可读状态
              channel.register(selector, SelectionKey.OP_READ);
              System.out.println(message);
          }
      }
      2.客户端逻辑
      public class ChatClient {
      
          public void start(String name) throws IOException {
              SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8088));
              socketChannel.configureblocking(false);
              Selector selector = Selector.open();
              socketChannel.register(selector, SelectionKey.OP_READ);
      
              // 监听服务端发来得消息
              new Thread(new ClientThread(selector)).start();
              // 监听用户输入
              Scanner scanner = new Scanner(System.in);
              while (scanner.hasNextLine()) {
                  String message = scanner.nextLine();
                  if (StringUtils.hasText(message)) {
                      socketChannel.write(StandardCharsets.UTF_8.encode(name + ": " + message));
                  }
              }
          }
      }
      3.客户端
      public class Client1 {
          public static void main(String[] args) throws IOException {
              new ChatClient().start("李四");
          }
      }
      public class Client2 {
          public static void main(String[] args) throws IOException {
              new ChatClient().start("张三");
          }
      }

      三、重要组件

      • Spring Core:Spring的核心组件,提供IOC、AOP等基础功能,是Spring全家桶的基础。
      • Spring Boot:一个基于Spring Framework的快速开发框架,可以快速创建独立的、生产级别的Spring应用程序。
      • Spring Cloud:一个用于构建分布式应用程序的框架,提供了诸如服务发现、配置管理、负载均衡等功能。
      • Spring Data:用于简化数据访问层开发的框架,提供了一系列数据访问模板和持久化技术的集成。
      • Spring Security:一个用于处理应用程序安全的框架,提供了认证、授权、安全防护等功能。
      • Spring Integration:Spring Integration是一个用于构建企业级集成解决方案的框架,支持将不同的应用程序和服务集成到一起。它提供了许多组件和模式,如消息通道、消息端点、消息路由器、过滤器等。
      • Spring BATch:Spring Batch是一个用于处理大量数据和批处理作业的框架。它提供了各种工具和组件,如任务启动器、作业仓库、作业执行器、步骤处理器、读写器等。
      • Spring Web Services:Spring Web Services是一个用于构建基于SOAP协议的Web服务的框架。它提供了各种组件和工具,如消息处理器、绑定器、端点等,使得构建Web服务更加容易。

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号