一、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服务更加容易。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论