一、pom文件、配置文件

1、pom文件

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

demo

springboot

0.0.1-SNAPSHOT

jar

springboot

Demo project for Spring Boot

spring-boot-starter-parent

org.springframework.boot

1.5.7.RELEASE

UTF-8

UTF-8

1.8

org.springframework.boot

spring-boot-starter-test

test

mysql

mysql-connector-java

runtime

org.springframework.boot

spring-boot-maven-plugin

2、配置文件

SpringBoot 支持以下几种类型的配置文件: application.properties:基于属性键值对的配置文件,使用简单的 key=value 格式,可读性较高。 application.yml:基于 YAML 格式的配置文件,使用缩进和冒号表示属性的层次结构,可读性更好。 application.yaml:与 application.yml 相同,只是文件扩展名不同。优先级从高到低 properties -> yml -> yamlbootstrap.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容器

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-tomcat

org.springframework.boot

spring-boot-starter-jetty

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容器 

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-tomcat

org.springframework.boot

spring-boot-starter-undertow

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.配置

io.netty

netty-all

4.1.36.Final

# 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 {

@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 selectionKeySet = selector.selectedKeys();

Iterator 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服务更加容易。

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: