桥下の民 - 微服务 & 框架
type: channel
link: https://wordplay.work/index.php/category/微服务-框架
items: LangChain4J 概述 & 起步
items: Skywalking
items: SpringBoot启动配置原理
items: Mapstruct使用教程
items: SpringBoot循环依赖
items: 自定义Starter
items: 优雅停止SpringBoot服务
items: Mina网络通信框架示例
items: Mina网络通信框架
items: SpringBoot--web开发

LangChain4J 概述 & 起步
type: item
date: 2025-08-19T06:49:00+00:00
description: 一、概述 1.1、概述 LangChain4J 即 LangChain For Java。 随着人工智能（AI）技术的迅猛发展，越来越多的开发者开始将目光投向AI应用的开发。然而，目前市场上大多数AI框架和工具如LangChain、PyTorch等主要支持Python，而Java开发者常常面临工具缺乏和学习门槛较高的问题。 LangChain4J 官方文档 1.2、作用 LLM 大模型应用技术架构： 大模型开发分类：超级个体+智能体、行业垂直大模型、基础通用大模型。 产品定位： 二、起步 2.1、前置约定 2.1.1、langchain4j 执行的各种大语言模型(LLMS) Comparison Table of all supported Language Models 2.1.2、模型约定 2.1.3、配置及关键点 所有调用均基于 OpenAI 协议标准或者 SrpingBoot 官方推荐整合规则，实现一致的接口设计与规范，确保多模型切换的便利性，提供高度可扩展的开发支持。 2.2、入门 2.2.1、接入按理百炼平台的通义模型 https://bailian.console.aliyun.com 2.2.2、大模型调用 1、获得 API-key 2、获得模型名 3、获得 baseUrl 开发地址

Skywalking
type: item
date: 2025-03-21T02:48:00+00:00
description: 一、Skywalking skywalking 是一个优秀的国产开源框架，2015 年由个人吴晟（华为开发者）开源 ， 2017 年加入 Apache 孵化器。 skywalking 支持 dubbo，SpringCloud，SpringBoot 集成，代码无侵入，通信方式采用 GRPC，性能较好，实现方式是 java 探针，支持告警，支持 JVM 监控，支持全局调用统计等等，功能较完善。 二、Skywalking & Spring Cloud Sleuth+ZipKin Skywalking 相比于 zipkin 还是有很大的优势的，如下： 1、Skywalking 采用字节码增强的技术实现代码无侵入，zipKin 代码侵入性比较高。 2、Skywalking 功能比较丰富，报表统计，UI 界面更加人性化。 三、Skywalking 架构 skywalking 和 zipkin 一样，也分为服务端和客户端，服务端负责收集日志数据并且展示，架构如下： 上述架构图中主要分为四个部分，如下： 上面的 Agent：负责收集日志数据，并且传递给中间的 OAP 服务器 中间的 OAP：负责接收 Agent 发送的 Tracing 和 Metric 的数据信息，然后进行分析 (Analysis Core) ，存储到外部存储器 ( Storage )，最终提供查询 ( Query ) 功能。 左面的 UI：负责提供 web 控制台，查看链路，查看各种指标，性能等等。 右面 Storage：负责数据的存储，支持多种存储类型。 Agent 负责收集日志传输数据，通过 GRPC 的方式传递给 OAP 进行分析并且存储到数据库中，最终通过 UI 界面将分析的统计报表、服务依赖、拓扑关系图展示出来。 三、服务端搭建 skywalking 同样是通过 jar 包方式启动，需要下载 jar 包，地址： https://skywalking.apache.org/downloads/ https://archive.apache.org/dist/skywalking 3.1、下载安装包 选择 V8.7.0 或其他版本，如下图： 重要的目录结构分析如下： agent：客户端需要指定的目录，其中有一个 jar，就是负责和客户端整合收集日志 bin：服务端启动的脚本 config：一些配置文件的目录 logs：oap 服务的日志目录 oap-libs：oap 所需的依赖目录 webapp：UI 服务的目录 3.2、配置修改 启动之前需要对配置文件做一些修改，修改如下： 3.2.1、/config/application.yml 这个是 oap 服务的配置文件，需要修改注册中心为 nacos，如下图： 配置 1：修改默认注册中心选择 nacos，这样就不用在启动参数中指定了。 配置 2：修改 nacos 的相关配置，由于陈某是本地的，则不用改动，根据自己情况修改。 3.2.2、webapp/webapp.yml 这个是 UI 服务的配置文件，其中有一个 server.port 配置，是 UI 服务的端口，默认 8080，可将其改成 8081，避免端口冲突。 3.3、启动服务 启动命令在 /bin 目录下，这里需要启动两个服务，如下： oap 服务：对应的启动脚本 oapService.bat，Linux 下对应的后缀是 sh。 UI 服务：对应的启动脚本 webappService.bat，Linux 下对应的后缀是 sh。 当然还有一个 startup.bat 启动文件，可以直接启动上述两个服务，我们可以直接使用这个脚本，直接双击，将会弹出两个窗口则表示启动成功。 此时直接访问：http://localhost:8888/，直接进入 UI 端。 四、客户端搭建 客户端也就是单个微服务，由于 Skywalking 采用字节码增强技术，因此对于微服务无代码侵入，只要是普通的微服务即可，不需要引入什么依赖。 想要传输数据必须借助 skywalking 提供的 agent，只需要在启动参数指定即可，命令如下： -javaagent:E:\SOFTWARE\skywalking\apache-skywalking-apm-bin\agent\skywalking-agent.jar -Dskywalking.agent.service_name=jeecg-cloud-gateway -Dskywalking.collector.backend_service=localhost:11800 上述命令解析如下： -javaagent：指定 skywalking 中的 agent 中的 skywalking-agent.jar 的路径。 -Dskywalking.agen…

SpringBoot启动配置原理
type: item
date: 2023-10-04T12:27:00+00:00
description: 一、创建SpringApplication对象 initialize(sources);//创建对象 private void initialize(Object[] sources) { //【保存主配置类】 if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //【判断当前是否一个web应用】 this.webEnvironment = deduceWebEnvironment(); //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer；然后保存起来 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //从多个配置类中找到有main方法的主配置类 this.mainApplicationClass = deduceMainApplicationClass(); } 拿到初始化器： 保存初始化器和监听器： 二、运行run方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); //获取SpringApplicationRunListeners；从类路径下META-INF/spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); //回调所有的获取SpringApplicationRunListener.starting()方法 listeners.starting(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //创建环境完成后回调SpringApplicationRunListener.environmentPrepared()；表示环境准备完成 Banner printedBanner = printBanner(environment); //创建ApplicationContext；决定创建web的ioc还是普通的ioc context = createApplicationContext(); analyzers = new FailureAnalyzers(context); //准备上下文环境;将environment保存到ioc中；而且applyInitializers()； //applyInitializers()：回调之前保存的所有的ApplicationContextInitializer的initialize方法 //回调所有的SpringApplicationRunListener的contextPrepared()； // prepareContext(context, environment, listeners, applicationArguments, printedBanner); //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded（）； //s刷新容器；ioc容器初始化（如果是web应用还会创建嵌入式的Tomcat）；Spring注解版 //扫描，创建，加载所有组件的地方；（配置类，组件，自动配置） refreshC…

Mapstruct使用教程
type: item
date: 2023-07-28T08:04:00+00:00
description: 一、简介 MapStruct是一个Java注释处理器，用于生成类型安全的bean映射类。 定义一个映射器接口，该接口声明任何必需的映射方法。在编译期间，MapStruct将生成此接口的实现。此实现使用简单的Java方法调用在源对象和目标对象之间进行映射，即没有反射或类似内容。 与手动编写映射代码相比，MapStruct通过生成繁琐且易于出错的代码来节省时间。遵循配置方法上的约定，MapStruct使用合理的默认值，但在配置或实现特殊行为时不加理会。 与动态映射框架相比，MapStruct具有以下优点： 1、通过使用普通方法调用（settter/getter）而不是反射来快速执行 2、编译时类型安全性：只能映射相互映射的对象和属性，不能将order实体意外映射到customer DTO等。 3、如果有如下问题，编译时会抛出异常 映射不完整（并非所有目标属性都被映射） 映射不正确（找不到正确的映射方法或类型转换） 4、可以通过freemarker定制化开发 二、设置 MapStruct是基于JSR 269的Java注释处理器，因此可以在命令行构建（javac，Ant，Maven等）以及您的IDE中使用。 它包含以下工件： org.mapstruct：mapstruct：包含必需的注释，例如@Mapping org.mapstruct：mapstruct-processor：包含注释处理器，该注释处理器生成映射器实现 2.1、Maven <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.0.Beta1</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.0.Beta1</version> </dependency> Lombok依赖：（版本最好在1.16.16以上，否则会出现问题）通常是和lombok一起使用。 <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <version>${lombok.version}</version> // 版本号 1.18.12 </dependency> idea中下载 mapstruct support 插件，安装重启Idea 。 三、映射器 3.1、基本映射 要创建映射器，只需使用所需的映射方法定义一个Java接口，并用注释对其进行org.mapstruct.Mapper注释： 该@Mapper注释将使得MapStruct代码生成器创建的执行PersonMapper 过程中生成时的界面。 在生成的方法实现中，源类型（例如Person）的所有可读属性都将被复制到目标类型（例如PersonDTO）的相应属性中： 当一个属性与其目标实体对应的名称相同时，它将被隐式映射。 当属性在目标实体中具有不同的名称时，可以通过@Mapping注释指定其名称。 @Data public class Person { String describe; private String id; private String name; private int age; private BigDecimal source; private double height; private Date createTime; } @Data public class PersonDTO { String describe; private Long id; private String personName; private String age; private String source; private String height; } // mapper @Mapper public interface PersonMapper { PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class); @Mapping(target = "name", source = "personName") @Mapping(target = "id", ignore = true) // 忽略id，不进行映射 PersonDTO conver(Person person); } 生成的实现类： public class Pers…

SpringBoot循环依赖
type: item
date: 2023-06-28T13:10:00+00:00
description: 一、概述 1.1、循环依赖 一个或多个对象之间存在直接或间接的依赖关系，这种依赖关系构成一个环形调用，有下面 3 种方式。 一个 demo： @Service public class Louzai1 { @Autowired private Louzai2 louzai2; public void test1() { } } @Service public class Louzai2 { @Autowired private Louzai1 louzai1; public void test2() { } } 这是一个经典的循环依赖，它能正常运行。 1.2、三级缓存 解读源码流程之前，spring 内部的三级缓存逻辑必须了解。 第一级缓存：singletonObjects，用于保存实例化、注入、初始化完成的 bean 实例； 第二级缓存：earlySingletonObjects，用于保存实例化完成的 bean 实例； 第三级缓存：singletonFactories，用于保存 bean 创建工厂，以便后面有机会创建代理对象。 执行逻辑： 先从“第一级缓存”找对象，有就返回，没有就找“二级缓存”； 找“二级缓存”，有就返回，没有就找“三级缓存”； 找“三级缓存”，找到了，就获取对象，放到“二级缓存”，从“三级缓存”移除。 1.3、原理执行流程 整个执行逻辑如下： 1、在第一层中，先去获取 A 的 Bean，发现没有就准备去创建一个，然后将 A 的代理工厂放入“三级缓存”（这个 A 其实是一个半成品，还没有对里面的属性进行注入），但是 A 依赖 B 的创建，就必须先去创建 B； 2、在第二层中，准备创建 B，发现 B 又依赖 A，需要先去创建 A； 3、在第三层中，去创建 A，因为第一层已经创建了 A 的代理工厂，直接从“三级缓存”中拿到 A 的代理工厂，获取 A 的代理对象，放入“二级缓存”，并清除“三级缓存”； 4、回到第二层，现在有了 A 的代理对象，对 A 的依赖完美解决（这里的 A 仍然是个半成品），B 初始化成功； 5、回到第一层，现在 B 初始化成功，完成 A 对象的属性注入，然后再填充 A 的其它属性，以及 A 的其它步骤（包括 AOP），完成对 A 完整的初始化功能（这里的 A 才是完整的 Bean）。 6、将 A 放入“一级缓存”。 二、源码 2.1、代码入口 2.2、第一层 进入 doGetBean()，从 getSingleton() 没有找到对象，进入创建 Bean 的逻辑。 进入 doCreateBean() 后，调用 addSingletonFactory()。 往三级缓存 singletonFactories 塞入 louzai1 的工厂对象。 进入到 populateBean()，执行 postProcessProperties()，这里是一个策略模式，找到下图的策略对象。 正式进入该策略对应的方法。 下面都是为了获取 louzai1 的成员对象，然后进行注入。 进入 doResolveDependency()，找到 louzai1 依赖的对象名 louzai2。 需要获取 louzai2 的 bean，是 AbstractBeanFactory 的方法。 正式获取 louzai2 的 bean。 到这里，第一层套娃基本结束，因为 louzai1 依赖 louzai2，下面我们进入第二层套娃。 2.3、第二层 2.4、第三层 三、解析 “一级缓存”的作用，变量命名为 singletonObjects，结构是 Map<String, Object>，它就是一个单例池，将初始化好的对象放到里面，给其它线程使用，如果没有第一级缓存，程序不能保证 Spring 的单例属性。 “三级缓存”的作用，变量命名为 singletonFactories，结构是 Map<String, ObjectFactory<?>>，Map 的 Value 是一个对象的代理工厂，所以“三级缓存”的作用，其实就是用来存放对象的代理工厂。 那这个对象的代理工厂有什么作用呢，我先给出答案，它的主要作用是存放半成品的单例 Bean，目的是为了“打破循环”。 为什么“三级缓存”不直接存半成品的 A，而是要存一个代理工厂呢 ？答案是因为 AOP。 那“二级缓存”的作用就清楚了，就是用来存放对象工厂生成的对象，这个对象可能是原对象，也可能是个代理对象。 3.2、能去掉第 2 级缓存么 @Service public class A { @Autowired private B b; @Autowired private C c; public void test1() { } } @Service public class B { @Au…

自定义Starter
type: item
date: 2022-07-08T06:28:00+00:00
description: 一、关于Starter 1.1、是什么 Starter是Spring Boot中的一个非常重要的概念，Starter相当于模块，它能将模块所需的依赖整合起来并对模块内的Bean根据环境（ 条件）进行自动配置。 使用者只需要依赖相应功能的Starter，无需做过多的配置和依赖，Spring Boot就能自动扫描并加载相应的模块并设置默认值，做到开箱即用。 1.2、Springboot 自动配置 SpringBoot中的starter是一种非常重要的机制，能够抛弃以前繁杂的配置，将其统一集成进starter，应用者只需要在maven中引入starter依赖，Spring Boot就能自动扫描各个jar包下classpath路径的spring.factories文件，加载自动配置类信息，加载相应的bean信息并启动相应的默认配置。 Spring Boot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置，并允许我们调整这些配置，即遵循“约定大于配置”的理念。 1.3、spring.factories Spring Boot会默认扫描跟启动类平级的包，如果我们的Starter跟启动类不在同一个主包下，需要通过配置spring.factories文件来配置生效，SpringBoot默认加载各个jar包下classpath路径的spring.factories文件，配置的key为： org.springframework.boot.autoconfigure.EnableAutoConfiguration 1.4、Starter开发常用注解 SpringBoot经过查找spring.factories文件，加载自动配置类，而自动配置类中定义了各种运行时判断条件，如@ConditionalOnMissingBean(A.class)等，只要ioc容器中没有指定的A类型的bean信息，该配置文件才会生效。 @Conditional是Spring4新提供的注解，它的作用是按照一定的条件进行判断，满足条件给容器注册bean。 属性映射注解： @ConfigurationProperties ：配置文件属性值和实体类的映射 @EnableConfigurationProperties : 和 @ConfigurationProperties 配合使用，把 @ConfigurationProperties 修饰的类加入ioc容器。 配置bean注解： @Configuration : 标识该类为配置类，并把该类注入ioc容器 @Bean : 一般在方法上使用，声明一个bean，bean名称默认是方法名称，类型为返回值。 条件注解： @Conditional 是根据条件类创建特定的Bean，条件类需要实现Condition接口，并重写matches接口来构造判断条件。 @ConditionalOnBean 容器中存在指定bean，才会实例化一个Bean @ConditionalOnMissingBean 容器中不存在指定bean，才会实例化一个Bean @ConditionalOnClass 系统中有指定类，才会实例化一个Bean @ConditionalOnMissingClass 系统中没有指定类，才会实例化一个Bean @ConditionalOnExpression 当SpEl表达式为true的时候，才会实例化一个Bean @AutoConfigureAfter 在某个bean完成自动配置后实例化这个bean @AutoConfigureBefore 在某个bean完成自动配置前实例化这个bean @ConditionalOnJava 系统中版本是否符合要求 @ConditionalOnSingleCandidate 当指定的Bean在容器中只有一个，或者有多个但是指定了首选的Bean时触发实例化 @ConditionalOnResource 类路径下是否存在指定资源文件 @ConditionalOnWebApplication 是web应用 @ConditionalOnNotWebApplication 不是web应用 @ConditionalOnJndi JNDI指定存在项 @ConditionalOnProperty 配置Configuration的加载规则 prefix 配置属性名称的前缀 value 数组，获取对应property名称的值，与name不可同时使用 name 数组，可与prefix组合使用，组成完整的配置属性名称，与value不可同时使用 havingValue 比较获取到的属性值与havingValue给定的值是否相同，相同才加载配置 matc…

优雅停止SpringBoot服务
type: item
date: 2022-07-07T10:54:00+00:00
description: 一、直接杀死进程 ps -ef | grep ink-blog.jar kill -9 17186 二、 SpringBoot 提供的actuator的功能 可以执行shutdown, health, info等，默认情况下，actuator的shutdown是disable的，我们需要打开它。首先引入acturator的maven依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 然后将shutdown节点打开，也将/actuator/shutdown暴露web访问也设置上，除了shutdown之外还有health, info的web访问都打开的话将 management.endpoints.web.exposure.include=* 就可以。将如下配置设置到application.properties里边。设置一下服务的端口号为3333。 server.port=3333 management.endpoint.shutdown.enabled=true management.endpoints.web.exposure.include=shutdown 接下来，创建一个SpringBoot工程，然后设置一个bean对象，配置上PreDestroy方法。这样在停止的时候会打印语句。bean的整个生命周期分为创建、初始化、销毁，当最后关闭的时候会执行销毁操作。在销毁的方法中执行一条输出日志。 public class TerminateBean{ @PreDestroy publicvoid preDestroy() { System.out.println("TerminalBean is destroyed"); } } 做一个configuration，然后提供一个获取bean的方法，这样该bean对象会被初始化。 @Configuration public class ShutDownConfig{ @Bean public TerminateBean getTerminateBean() { return new TerminateBean(); } } 在启动类里边输出一个启动日志，当工程启动的时候，会看到启动的输出，接下来执行停止命令。 curl -X POST http://localhost:3333/actuator/shutdown 以下日志可以输出启动时的日志打印和停止时的日志打印，同时程序已经停止。 三、获取程序启动时候的context，然后关闭主程序启动时的context 这样程序在关闭的时候也会调用PreDestroy注解。 /* method 2: use ctx.close to shutdown all application context */ ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } ctx.close(); 四、在SpringBoot启动的时候将进程号写入一个app.pid文件，生成的路径是可以指定的 可以通过命令 cat /Users/test/app.id | xargs kill 命令直接停止服务，这个时候bean对象的PreDestroy方法也会调用的。这种方法大家使用的比较普遍。写一个start.sh用于启动springboot程序，然后写一个停止程序将服务停止。 /* method 3 : generate a pid in a specified path, while use command to shutdown pid : 'cat /Users/test/app.pid | xargs kill' */ SpringApplication application = new SpringApplication(ShutdowndemoApplication.class); application.addListeners(new ApplicationPidFileWriter("/Users/test/app.pid")); application.run(); 五、通过调用一个SpringApplication.exit(…

Mina网络通信框架示例
type: item
date: 2022-06-29T13:39:00+00:00
description: 一、功能 用 Mina 框架，同时实现服务器和客户端，实现客户端与客户端之间的 IM 通信，使用 Java JDBC 接口连入 MySQL 数据库。 二、数据库登录处理逻辑 package database; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.mina.core.session.IoSession; import util.MessageUtil; import util.SessionUtil; import common.Common; /** * 管理客户端的数据库 */ public class ClientJDBC { public ClientJDBC() { try { // 加载JDBC Driver Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * * 1、查询是否已存在此用户 * 2、注册，添加新数据 */ public void addNewData(String name, String password, IoSession loginSession) { try { // 建立连接 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/clientdb", "root", ""); // 创建Statement Statement statement = connection.createStatement(); // 查询是否已存在此用户 String selectSQL = "select password from client where name=" + "'" + name + "'"; ResultSet set = statement.executeQuery(selectSQL); // 如果不存在此用户 if (!set.next()) { // 添加数据 PreparedStatement preparedStatement = connection .prepareStatement("insert into client values(null,?,?)"); preparedStatement.setString(1, name); preparedStatement.setString(2, password); preparedStatement.executeUpdate(); // 提示用户注册成功 loginSession.write(Common.CANREG); } else { // 提示用户已注册 loginSession.write(Common.CANTRE); } connection.close(); } catch (SQLException e) { e.printStackTrace(); } } /** * * 1、查询帐号密码是否匹配 * 2、查询是否用户已登录 * 3、登录 */ public boolean login(String name, String password, IoSession userSession) { try { // 建立连接 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/clientdb", "root", ""); // 创建Statement Statement statement = connection.createStatement(); // 查询是否已存在此用户 String selectSQL = "select password from client where name=" + "'" + name + "'"; ResultSet set = statement.executeQuery(selectSQL); // 如果存在此用户 if (set.next()) { // 密码匹配成功 if (set.getString("password…

Mina网络通信框架
type: item
date: 2022-06-29T13:16:00+00:00
description: 一、关于 由于传统的 Socket 网络编程基于一个线程对应一个客户端的实现方式，大量的线程创建和销毁导致性能下降，无法应对高并发量的访问，所以基于服务器端的网络通信开发，我们常用 Mina 网络通信框架，即常说的 Java NIO ( java non-blocking IO ) 开发。 Mina 的几个重要接口： •IoServiece ：这个接口在一个线程上负责套接字的建立，拥有自己的 Selector，监听是否有连接被建立。 •IoProcessor ：这个接口在另一个线程上负责检查是否有数据在通道上读写，也就是说它也拥有自己的 Selector，这是与我们使用 JAVA NIO 编码时的一个不同之处，通常在 JAVA NIO 编码中，我们都是使用一个 Selector，也就是不区分 IoService与 IoProcessor 两个功能接口。另外，IoProcessor 负责调用注册在 IoService 上的过滤器，并在过滤器链之后调用 IoHandler。 •IoAccepter ：相当于网络应用程序中的服务器端 •IoConnector ：相当于客户端 •IoSession ：当前客户端到服务器端的一个连接实例 •IoHandler ：这个接口负责编写业务逻辑，也就是接收、发送数据的地方。这也是实际开发过程中需要用户自己编写的部分代码。 •IoFilter ：过滤器用于悬接通讯层接口与业务层接口，这个接口定义一组拦截器，这些拦截器可以包括日志输出、黑名单过滤、数据的编码（write 方向）与解码（read 方向）等功能，其中数据的 encode与 decode是最为重要的、也是你在使用 Mina时最主要关注的地方。 Mina 的一个重要的类 IoHandlerAdapter，此类仅仅是实现了 IoHandler 接口，但并不做任何处理。 一个 IoHandler 接口中具有如下一些方法（摘自 MINA 的 API 文档）： •void exceptionCaught(IoSession session, Throwable cause) 当接口中其他方法抛出异常未被捕获时触发此方法 •void messageReceived(IoSession session, Object message) 当接收到客户端的请求信息后触发此方法 •void messageSent(IoSession session, Object message) 当信息已经传送给客户端后触发此方法 •void sessionClosed(IoSession session) 当连接被关闭时触发，例如客户端程序意外退出等等 •void sessionCreated(IoSession session) 当一个新客户端连接后触发此方法 •void sessionIdle(IoSession session, IdleStatus status) 当连接空闲时触发此方法 •void sessionOpened(IoSession session) 当连接后打开时触发此方法，一般此方法与 sessionCreated 会被同时触发 二、开发流程 Mina 服务器网络通信框架开发流程： 1、导入相关 jar 包: mina-core-2.0.13.jar、slf4j-api-1.7.14.jar 2、创建acceptor，绑定Handler，设置Filter，绑定端口。 NioSocketAcceptor acceptor = new NioSocketAcceptor(); acceptor.setHandler(new MyServerHandler()); // 获取拦截器，拦截器作用：把字节转成对象 // TextLineCodecFactory 把数据进行加解码 acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); // 5秒钟服务器和客户端没有进行读写，则进入空闲状态Idle acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5); //绑定9898端口 acceptor.bind(new InetSocketAddress(9898)); 3、创建自定义的Handler。 package com.example.server; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus…

SpringBoot--web开发
type: item
date: 2022-06-26T06:54:00+00:00
description: 一、简介 1.1、使用SpringBoot 1）创建SpringBoot应用，选中我们需要的模块； 2）SpringBoot已经默认将这些场景配置好了，只需要在配置文件中指定少量配置就可以运行起来。 3）自己编写业务代码； 自动配置原理： 这个场景SpringBoot帮我们配置了什么？能不能修改？能修改哪些配置？能不能扩展？ xxxxAutoConfiguration 给容器中自动配置组件 xxxxProperties 配置类来封装配置文件的内容 1.2、SpringBoot对静态资源的映射 @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware { //可以设置和静态资源有关的参数，缓存时间等 WebMvcAuotConfiguration： @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } Integer cachePeriod = this.resourceProperties.getCachePeriod(); if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration( registry.addResourceHandler("/webjars/**") .addResourceLocations( "classpath:/META-INF/resources/webjars/") .setCachePeriod(cachePeriod)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); //静态资源文件夹映射 if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration( registry.addResourceHandler(staticPathPattern) .addResourceLocations( this.resourceProperties.getStaticLocations()) .setCachePeriod(cachePeriod)); } } //配置欢迎页映射 @Bean public WelcomePageHandlerMapping welcomePageHandlerMapping( ResourceProperties resourceProperties) { return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(), this.mvcProperties.getStaticPathPattern()); } //配置喜欢的图标 @Configuration @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) public static class FaviconConfiguration { private final ResourceProperties resourceProperties; public FaviconConfiguration(ResourceProperties resourceProperties) { this.resourceProperties = resourceProperties; } @Bean public SimpleUrlHandlerMapping faviconHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); //所有 *…