SpringBoot的pom文件、容器、组件

一、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的启动

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,适合处理少数非常繁忙的链接。

 1.Tomcat组成、架构

(1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个 Connector(链接) 和一个 Container(容器);
(2)Server 掌管着整个Tomcat的生死大权;
(4)Service 是对外提供服务的;
(5)Connector 用于接受请求并将请求封装成Request和Response来具体处理;
(6)Container 用于封装和管理Servlet,以及具体处理request请求;

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聊天应用等

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.accesslog.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(ChannelHandlerContext 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());
        // 添加上自己的处理器
        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) selectionKey.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服务更加容易。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要搭建一个Spring Boot项目并验证Spring Boot容器特性,你可以按照以下步骤进行操作: 要求1:搭建的流程 1. 首先,确保你已经安装了Java开发环境(JDK)和Maven构建工具。 2. 创建一个新的Maven项目。你可以使用命令行工具或者IDE(如IntelliJ IDEA、Eclipse等)来创建。 3. 在项目的pom.xml文件中添加Spring Boot的依赖。你可以在Spring官方网站上找到最新的依赖信息。 4. 创建一个Spring Boot的启动类。这个类需要使用`@SpringBootApplication`注解进行标记。这个注解会自动配置Spring Boot应用程序,并进行必要的组件扫描。 5. 编写你的业务逻辑代码。你可以创建Controller、Service、Repository等组件来实现你的功能。 6. 运行你的Spring Boot应用程序。你可以使用命令行或者IDE来运行。 要求2:代码验证 在你的Spring Boot应用程序中,你可以通过以下方式验证Spring Boot容器特性: 1. 创建一个新的Controller类,并使用`@RestController`注解进行标记。这个注解会将这个类标记为一个RESTful风格的控制器。 2. 在Controller类中创建一个处理HTTP请求的方法,例如`hello()`方法。你可以使用`@RequestMapping`注解来指定处理的URL路径和请求方法。 3. 在`hello()`方法中返回一个字符串,例如"Hello, Spring Boot!"。 4. 运行你的应用程序并访问`http://localhost:8080/hello`路径。你应该能够看到浏览器或者HTTP客户端返回的"Hello, Spring Boot!"字符串。 通过以上步骤,你可以搭建一个Spring Boot项目并验证Spring Boot容器特性。请注意,这只是一个简单的示例,你可以根据自己的需求进行更复杂的开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值