Spring Boot扩展

在Spring Boot中可以集成第三方的框架如MyBatis、MyBatis-Plus和RabbitMQ等统称为扩展。每一个扩展会封装成一个集成,即Spring Boot的starter(依赖组件)。starter是一种非常重要的机制,不需要烦琐的配置,开发者只需要在项目的依赖中加入starter依赖,Spring Boot就能根据依赖信息自动扫描到要加载的信息并启用相应的默认配置。starter的出现让开发者不再需要查找各种依赖库及相应的配置。所有stater模块都遵循着约定成俗的默认配置,并允许自定义配置,即遵循“约定大于配置”的原则。

常用的starter及其说明如表6.1所示。

表6.1 Spring Boot的starter列表

日志管理

项目的日志主要包括系统日志、应用程序日志和安全日志。运维人员和项目开发人员可以通过日志了解服务器软/硬件信息,检查配置过程中的错误及错误发生的原因。通过分析日志还可以了解服务器的负荷、性能安全性,从而及时采取措施解决发生的问题。

因此,项目人员需要在系统开发和运行时保存日志。关于什么时候保存日志有以下几个要点:

(1)系统初始化时:记录系统和服务的启动参数。在核心模块初始化过程中会依赖一些关键配置项,根据参数不同提供不同的服务,记录当前的参数有助于发生错误后排除问题。

(2)系统提示异常:代码中的异常捕获机制,此类异常的错误级别非常高,是系统在告知开发人员需要关注的错误信息。一般用WARN或者ERROR级别来记录当前的错误日志。

(3)业务流程预期不符:记录与正常流程不同的业务参数,如外部参数不正确、未知的请求信息等。

(4)系统核心角色和组件的关键动作的记录:包括核心业务的日志记录,INFO级别的日志记录,保存微服务各服务节点交互的数据日志记录、系统核心数据表的增、删、改操作的日志记录,以及核心组件运行情况的日志记录等。

(5)第三方服务远程调用:对第三方的服务调用需要保存调用前后的日志记录,方便在发生错误时排查问题。

常用的日志框架

在Java项目开发过程中,最简单的方式是使用System.out.println打印日志,但这种方式有很多缺陷,如I/O瓶颈,而且不利于日志的统一管理。目前市面上有很多日志组件可以集成到Spring Boot中,它们能够快速地实现不同级别的日志分类,以及在不同的时间进行保存。常用的日志框架有以下几个:

1. JUL简介

JUL即java.util.logging.Logger,是JDK自带的日志系统,从JDK 1.4开始出现。其优点是系统自带,缺点是相较于其他的日志框架来说功能不够强大。

2. Apache Commons Logging简介

Apache Commons Logging是Apache提供的一个通用日志API,可以让程序不再依赖于具体的日志实现工具。Apache Commons Logging包中还对其他日志工具(包括Log4j、JUL)进行了简单的包装,可以让应用程序在运行时直接将Apache Commons Logging适配到对应的日志实现工具中。

提示:Apache Common Logging通过动态查找机制,在程序运行时会自动找出真正使用的日志库。这一点与SLF4J不同,SLF4J是在编译时静态绑定真正的Log实现库。

3. Log4j简介

Log4j是Ceki Gülcü实现出来的,后来捐献给Apache,又被称为Log4j1.x,它是Apache的开放源代码项目。在系统中使用Log4j,可以控制日志信息输送的目的地是控制台、文件及数据库等,还可以自定义每一条日志的输出格式,通过定义每一条日志信息的级别,还可以控制日志的生成过程。

Log4j主要是由Loggers(日志记录器)、Appender(输出端)和Layout(日志格式化器)组成。其中:

Logger用于控制日志的输出级别与是否输出日志;

Appender用于指定日志的输出方式(输出到控制台、文件等);Layout用于控制日志信息的输出格式。

Log4j有7种不同的log级别,按照等级从低到高依次为TRACE、DEBUG、INFO、WARN、ERROR、FATAL和OFF。如果配置为OFF级别,表示关闭log。

Log4j支持两种格式的配置文件:properties和XML。

4. Logback简介

Logback是由log4j的创立者Ceki Gülcü设计,是Log4j的升级版。

Logback当前分成3个模块:logback-core、logback- classic和logbackaccess。logback-core是另外两个模块的基础模块。logback-classic是Log4j的一个改良版本,目前依然建议在生产环境中使用。

5. Log4j2简介

Log4j2也是由log4j的创立者Ceki Gulcu设计的,它是Log4j 1.x和Logback的改进版。在项目中使用Log4j2作为日志记录的组件,在日志的吞吐量和性能方面比log4j 1.x提高了10倍,并可以解决一些死锁的Bug,配置也更加简单、灵活。

6. SLF4J

SLF4J是对所有日志框架制定的一种规范、标准和接口,并不是一个具体框架。因为接口并不能独立使用,需要和具体的日志框架配合使用(如Log4j2、Logback)。使用接口的好处是,当项目需要更换日志框架时,只需要更换jar和配置,不需要更改相关的Java代码,SLF4J相当于Java设计模式的门面模式。目前项目的开发中多使用SLF4J+Logback或者SLF4J+Log4J2的组合方式来记录日志。

日志的输出级别

日志的输出是分级别的,不同的日志级别在不同的场合打印不同的日志。常见的日志级别有以下4个:DEBUG:该级别的日志主要输出与调试相关的内容,主要在开发、测试阶段输出。DEUBG日志应尽可能详细,开发者会把各类详细信息记录到DEBUG里,起到调试的作用,包括参数信息、调试细节信息、返回值信息等,方便在开发、测试阶段出现问题或者异常时对问题进行分析和修改。

INFO:该级别的日志主要记录系统关键信息,用来保留系统正常工作期间的关键信息指标。开发者可以将初始化系统配置、业务状态变化信息或者用户业务流程中的核心处理记录到INFO日志中,方便运维及错误回溯时进行场景复现。当在项目完成后,一般会把项目日志级别从DEBUG调成INFO,对于不需要再调试的日志,将通过INFO级别的日志记录这个应用的运行情况,如果出现问题,根据记录的INFO级别的日志来排查问题。

WARN:该级别的日志主要输出警告性质的内容,这类日志可以预知问题的发生,如某个方法入参为空或者参数的值不满足运行方法的条件时。在输出WARN级别的日志时应输出详尽的提示信息,方便开发者和运维人员对日志进行分析。

ERROR:该级别主要指系统错误信息,如错误、异常等。例如,在catch中抓获的网络通信和数据库连接等异常,若异常对系统的整个流程影响不大,可以输出WARN级别的日志。在输出ERROR级别的日志时,要记录方法入参和方法执行过程中产生的对象等数据,在输出带有错误和异常对象的数据时,需要将该对象全部记录,方便后续的Bug修复。

日志的等级由低到高分别是DEBUG<INFO<WARN<ERROR,日志记录一般会记录设置级别及其以下级别的日志。例如,设置日志的级别为INFO,则系统会记录INFO和DEBUG级别的日志,超过INFO级别的日志不会记录。

综上所述,在项目中保存好日志有以下好处:

打印调试:用日志记录变量或者逻辑的变化,方便进行断点调试。

问题定位:程序出现异常后可根据日志快速定位问题所在,方便后期解决问题。

用户行为日志:记录用户的关键操作行为。重要系统逻辑日志记录:方便以后问题的排查和记录。

实战:日志管理之使用AOP记录日志

本小节将新建一个项目,实现使用日志组件和Spring的AOP记录所有Controller入参的功能,本次使用SLF4J+log4j2的方式实现日志的记录。

(1)新建一个项目spring-extend-demo,在pom.xml中添加Web、Log4j2、SLF4J和AOP的依赖坐标,具体如下:

<?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

https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.3.10.RELEASE</version>

<relativePath/> <!-- lookup parent from repository -->

</parent>

<groupId>com.example</groupId>

<artifactId>spring-extend-demo</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>spring-extend-demo</name>

<description>Demo project for Spring Boot</description>

<properties>

<java.version>11</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter

logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

<exclusions>

<exclusion>

<groupId>org.junit.vintage</groupId>

<artifactId>junit-vintage-engine</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-log4j2</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter

logging</artifactId>

</exclusion>

</exclusions>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

</project>

添加完依赖后,可以查看项目的依赖库,部分依赖库如图6.1和图6.2所示,当前项目中已经引入了SLG4J和Log4j2依赖。

图6.2 SLF4J的依赖

(2)在resources目录下新建一个log4j2.xml配置文件,配置日志的记录如下:

<?xml version="1.0" encoding="UTF-8"?>

<!--

Configuration后面的配置,用于设置log4j2内部的信息输出,可以不设置。当设置成

trace时可以看到log4j2内部的各种详细输出。

-->

<!--

monitorInterval:Log4j能够自动检测、修改配置文件,并设置间隔秒数。

-->

<configuration status="error" monitorInterval="30">

<!--先定义所有的Appender-->

<appenders>

<!--这个输出控制台的配置-->

<Console name="Console" target="SYSTEM_OUT">

<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝

(onMismatch)-->

<ThresholdFilter level="trace" onMatch="ACCEPT"

onMismatch="DENY"/>

<!--输出日志的格式-->

<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level

%class{36} %L%M - %msg%xEx%n"/>

</Console>

<!--文件会打印出所有信息,该日志在每次运行程序时会自动清空,由append属性

决定,适合临时测试用-->

<File name="log" fileName="log/test.log" append="false">

<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level

%class{36} %L%M - %msg%xEx%n"/>

</File>

<!-- 打印出所有的信息,如果大小超过size,则超出部分的日志会自动存入按年

份-月份建立的文件夹下面并进行压缩作为存档-->

<RollingFile name="RollingFile" fileName="D:/log/log.log"

filePattern="D:/log/log-${date:yyyy-MM}/log-

%d{MM-dd-yyyy}-%i.log">

<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z}

%-5level%class{36} %L %M - %msg%xEx%n"/> <!-- 如果一个文件超过50 MB,就会生成下一个日志文件 -->

<SizeBasedTriggeringPolicy size="50MB"/>

<!-- 如不设置DefaultRolloverStrategy属性,则默认同一文件夹下最多

有7个文件,这里设置为20 -->

<DefaultRolloverStrategy max="20"/>

</RollingFile>

</appenders>

<!--定义logger,只有定义了logger并引入上面配置的Appender,当前的Appender

才会生效-->

<loggers>

<!--建立一个默认用户的logger,将其作为日志记录的根配置-->

<root level="info">

<appender-ref ref="RollingFile"/>

<appender-ref ref="Console"/>

</root>

</loggers>

</configuration>

(3)配置保存成功后,每天会根据前面的配置生成一个日志文件,一个日志文件的最大容量为50MB,超过50MB就再新建一个日志文件。新建一个Web入口类HelloController,代码如下:

package com.example.springextenddemo.controller;

import com.example.springextenddemo.vo.UserVO;

import org.springframework.web.bind.annotation.*;

@RestController

public class HelloController {

@GetMapping("/hi")

public String hi(@RequestParam("name")String name){

return "hi "+name;

}

@PostMapping("/hi-post")

public String hiPost(@RequestBody UserVO userVO){ return "hi-post "+userVO;

}

}

Hellocontroller中的参数接收实体类UserVO如下:

package com.example.springextenddemo.vo;

import java.util.StringJoiner;

public class UserVO {

private String name;

private String address;

private int age;

//省略GET和SET方法

}

(4)新建一个AOP类记录日志:

package com.example.springextenddemo.aop;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.Signature;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.mvc.method.annotation.Extended

ServletRequestDataBinder;

import javax.servlet.http.HttpServletResponseWrapper;import java.util.HashMap;

import java.util.Map;

/**

* 第一个执行

*/

@Order(1)

/**

* aspect 切面

*/

@Aspect

@Component

public class RequestParamLogAop {

private static final Logger log =

LoggerFactory.getLogger(RequestParamLogAop.class);

/**

* Controller层切点

*/

@Pointcut("execution (*

com.example.springextenddemo.controller..*.*(..))")

public void controllerAspect() {

}

/**

* 环绕通知

*

* @param joinPoint

* @throws Throwable

*/

@Around(value = "controllerAspect()")

public Object around(ProceedingJoinPoint joinPoint) throws

Throwable {

Signature signature = joinPoint.getSignature();

methodBefore(joinPoint,signature);

Object result = joinPoint.proceed();

methodAfterReturn(result, signature);

return result;

} /**

* 方法执行前执行

*

* @param joinPoint

* @param signature

*/

private void methodBefore(JoinPoint joinPoint, Signature

signature) {

//在两个数组中,参数值和参数名的个数和位置是一一对应的

Object[] objs = joinPoint.getArgs();

// 参数名

String[] argNames = ((MethodSignature)

signature).getParameterNames();

Map<String, Object> paramMap = new HashMap<String, Object>();

for (int i = 0; i < objs.length; i++) {

if (!(objs[i] instanceof ExtendedServletRequestDataBinder)

&& !(objs[i] instanceof

HttpServletResponseWrapper)) {

paramMap.put(argNames[i], objs[i]);

}

}

log.info("请求前-方法:{} 的请求参数:{}", signature, paramMap);

}

/**

* 方法执行后的返回值

*/

private void methodAfterReturn(Object result, Signature signature)

{

log.info("请求后-方法:{} 的返回参数是:{}", signature, result);

}

}

(5)新建一个Spring Boot启动类:

package com.example.springextenddemo;

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class SpringExtendDemoApplication {

public static void main(String[] args) {

SpringApplication.run(SpringExtendDemoApplication.class,

args);

}

}

(6)修改配置文件application.properties,将日志配置文件添加到Spring Boot中:

logging.config=classpath:log4j2.xml

(7)启动项目,可以在控制台看到新的日志格式,如图6.3所示。

在浏览器中访问localhost:8080/hi?name= cc,结果如图6.4所示。

再访问localhost:8080/hi-post,结果如图6.5所示。

查看日志的配置目录,打开D:\log可以看到日志文件,如图6.6所示,日志内容如图6.7所示,控制台的输出日志和保存日志文件内容一样,如图6.8所示。

图6.7 log日志内容

图6.8 控制台打印的日志

过AOP简单地完成了对所有Controller入口的请求参数的记录,这个功能一般在项目中必须要有,请求入参必须进行记录,以方便问题的回溯。

实战:日志管理之自定义Appender

上面定义的日志配置使用的是Log4j2自带的日志Appender,在Log4j2中常用的Appender如表6.2所示,它们有不同的功能。

表6.2 Log4j2常用的Appender

在项目开发中可以直接使用上面的Appender,也可以自定义一个Appender。下面完成一个自定义的Appender,在打印的日志前面加上自定义的内容,完成自定义日志的开发。

(1)新建一个Appeder的实现类,此类需要继承自类AbstractAppender,代码如下:

package com.example.springextenddemo.appender;

import org.apache.logging.log4j.core.Filter;

import org.apache.logging.log4j.core.Layout;

import org.apache.logging.log4j.core.LogEvent;

import org.apache.logging.log4j.core.appender.AbstractAppender;

import org.apache.logging.log4j.core.config.plugins.Plugin;

import org.apache.logging.log4j.core.config.plugins.PluginAttribute;import org.apache.logging.log4j.core.config.plugins.PluginElement;

import org.apache.logging.log4j.core.config.plugins.PluginFactory;

import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.Serializable;

/**

* 自定义实现Appender

* @Plugin注解:在log4j2.xml配置文件中使用,指定的Appender Tag

*/

@Plugin(name = "myAppender", category = "Core", elementType =

"appender",

printObject = true)

public class MyLog4j2Appender extends AbstractAppender {

String printString;

/**

*构造函数 可自定义参数 这里直接传入一个常量并输出

*

*/

protected MyLog4j2Appender(String name, Filter filter, Layout<?

extends Serializable> layout,

String printString) {

super(name, filter, layout);

this.printString = printString;

}

/**

* 重写append()方法:在该方法里需要实现具体的逻辑、日志输出格式的设置

* 自定义实现输出

* 获取输出值:event.getMessage().toString()

* @param event

*/

@Override

public void append(LogEvent event) {

if (event != null && event.getMessage() != null) {

//格式化输出

System.out.print("自定义appender"+printString + ":" +

getLayout().toSerializable(event));

}

} /**

* 接收log4j2-spring.xml中的配置项

* @PluginAttribute 是XML节点的attribute值,如<book name="sanguo">

</book>,这里的name是attribute

* @PluginElement 表示XML子节点的元素,例如:

* <book name="sanguo">

* <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l -

%m%n"/>

* </book>

* 其中,PatternLayout是{@link Layout}的实现类

*/

@PluginFactory

public static MyLog4j2Appender createAppender(

@PluginAttribute("name") String name,

@PluginElement("Filter") final Filter filter,

@PluginElement("Layout") Layout<? extends Serializable>

layout,

@PluginAttribute("printString") String printString) {

if (name == null) {

LOGGER.error("no name defined in conf.");

return null;

}

//默认使用 PatternLayout

if (layout == null) {

layout = PatternLayout.createDefaultLayout();

}

//使用自定义的Appender

return new MyLog4j2Appender(name, filter, layout, printString);

}

@Override

public void start() {

System.out.println("log4j2-start方法被调用");

super.start();

}

@Override

public void stop() {

System.out.println("log4j2-stop方法被调用"); super.stop();

}

}

重写的start()方法为初始时调用,在数据库入库、连接缓存或者MQ时,可以在这个方法里进行初始化操作。stop()方法是在项目停止时调用,用来释放资源。

(2)将之前项目中的日志配置文件log4j.xml修改为log4j.xm.bak,再新建一个自定义的Appender的log4j2的配置文件。注意,自定义的Appender的名称要和Java代码中的Appender的名字相同,其配置文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration status="INFO" monitorInterval="30"

packages="com.example.

springextenddemo">

<!--定义Appenders-->

<appenders>

<myAppender name="myAppender" printString=":start log:">

<!--输出日志的格式-->

<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l -

%m%n"/>

</myAppender>

</appenders>

<!--自定义logger,只有定义了logger并引入appender,appender才会生效-->

<loggers>

<!--spring和mybatis的日志级别为info-->

<logger name="org.springframework" level="INFO"></logger>

<logger name="org.mybatis" level="INFO"></logger>

<!-- 如果在自定义包中设置为INFO,则可以看见输出的日志不包含debug输出了

-->

<logger name="com.example.springextenddemo" level="INFO"/>

<root level="all">

<appender-ref ref="myAppender"/>

</root> </loggers>

</configuration>

(3)重新启动项目,在浏览器中访问http://localhost:8080/hi?name=cc,可以看到控制台显示的自定义日志如图6.9所示。日志前已经加上了前缀自定义appender:start log,达到了本次自定义Appender的目的。

图6.9 自定义Appender输出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87521.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87521.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87521.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JSON-To-Video】AI智能体开发:为视频图片元素添加动效(滑入、旋转、滑出),附代码

各位朋友们&#xff0c;大家好&#xff01; 今天要教大家如何在 JSON - To - Video 中为视频内图片元素添加滑入、旋转、滑出的动效。 如果您还不会封装制作自己的【视频工具插件】&#xff0c;欢迎查看之前的教程&#xff01; AI智能体平台&#xff0c;如何封装自定义短视频…

Spring Boot(九十二):Spring Boot实现连接不上数据库就重启服务

场景: 在线上部署时,若服务器因断电等原因意外重启,项目及其依赖的数据库服务通常需要配置为自动启动。此时,如果数据库服务启动较慢或失败,Spring Boot 项目会因无法建立数据库连接而启动失败。 需求: 为确保项目启动成功,需要让 Spring Boot 项目等待数据库服务完全就…

Debian配置Redis主从、哨兵

前言 Redis的下载安装可参考Centos安装配置Redis6.x&#xff0c;Centos和Debian的步骤基本类似&#xff0c;或自行在网上搜索相关资料 注意&#xff1a;远程连接需放开相应端口 主从 搭建一个一主二从的主从模式 处理conf文件 #进入redis所在目录 cd /tools/redis/redis6 …

虚实交融:数字孪生如何重塑交通与公路勘察设计的未来

当每一条道路、每一座桥梁、每一盏信号灯都在数字世界获得“永生副本”&#xff0c;交通系统从被动响应迈入主动预演的纪元 一、数字孪生的核心定义&#xff1a;超越镜像的动态认知引擎 数字孪生&#xff08;Digital Twin&#xff09;并非简单的三维可视化模型&#xff0c;而是…

vector模拟实现中的迭代器失效问题

首先来看一组代码&#xff1a; iterator insert(iterator pos, const T& x) {// 扩容if (_finish _end_of_storage){size_t len pos - _stare;reserve(capacity() 0 ? 4 : capacity() * 2);pos _stare len;}iterator end _finish - 1;while (end > pos){*(end…

java 设计模式_行为型_22模板模式

22.模板模式 模板方法&#xff08;Template Method&#xff09;作为Java的设计模式之一&#xff0c;一个词概括其优势特点那就是&#xff1a;抽象步骤 首先我们应该抽出共通的东西做一个父类&#xff08;Base类&#xff09;&#xff0c;其次具体的蛋糕制作由子类进一步实现&…

随记:在springboot中websocket的使用

我现在有两种方法 第一种&#xff1a;使用java封装的这个包下的javax.websocket.* 先配置这个配置类 import com.alibaba.nacos.common.utils.CollectionUtils; import org.springframework.stereotype.Component;import javax.websocket.HandshakeResponse; import javax.w…

技术文章大纲:SpringBoot自动化部署实战

技术文章大纲&#xff1a;SpringBoot自动化部署实战 概述 自动化部署的背景与意义SpringBoot在现代化部署中的优势常见自动化部署工具与方案概览&#xff08;Jenkins、Docker、K8s等&#xff09; 环境准备 基础工具要求&#xff1a;JDK、Maven/Gradle、Git服务器环境配置&a…

FastAdmin按钮类功能全解析 class 属性定义不同的交互行为

在 FastAdmin 中&#xff0c;超链接的 class 属性用于定义不同的交互行为和样式。以下是常见 class 配置的用途和区别&#xff1a; btn-dialog 用于触发弹出对话框行为。点击带有此 class 的链接或按钮时&#xff0c;FastAdmin 会自动加载指定的 URL 内容并在模态框中显示。通…

python3字典对象实现解析

文章目录 前言Raymond的方案字典结构字典创建字典插入插入空字典PyDictKeysObject的创建设置索引存储entry 插入非空字典调整大小字典查找联合字典插入 字典查询字典删除 前言 本来以为python字典的实现就是一个哈希表的普通实现&#xff0c;所以在学习基本类型时没去仔细研究…

Word2Vec介绍

前言 当今的大语言模型非常智能&#xff0c;但是你有没有想过这些事情&#xff1a; 机器是怎么理解“国王”和“王后”之间的关系&#xff1f; “猫”和“狗”是怎么在 AI 中“相似以及区分”的&#xff1f; 文本又是怎么变成模型能读懂的数字&#xff1f; 这一切&#xf…

Rsync+sersync实现数据实时同步(小白的“升级打怪”成长之路)

目录 一、rsync部署 push推数据 1、编写rsync配置文件 2、备份测试 3、检验结果 二、rsyncsersync 实现数据实时同步 1、安装sersync服务 2、检验结果 pull拉取数据 1、编写rsync配置文件 2、检验结果 三、脚本编写 1、客户端脚本编写 2、服务器脚本编写 一、rsy…

用 python 开发一个可调用工具的 AI Agent,实现电脑配置专业评价

在人工智能时代&#xff0c;AI Agent凭借其强大的任务处理能力&#xff0c;逐渐成为开发人员手中的得力工具。今天&#xff0c;我们就来一起动手&#xff0c;用Python打造一个能够调用工具的AI Agent&#xff0c;实现根据电脑信息对电脑配置进行专业评价的功能。 一、项目创建…

WSL 安装使用和常用命令

参考官方使用说明&#xff1a; https://learn.microsoft.com/zh-cn/windows/wsl/ 安装wsl: wsl --install --no-distribution --no-distribution&#xff1a;安装 WSL 时不要安装分发版 更新 wsl: wsl --update 设置wsl 默认版本&#xff1a; wsl --set-default-version <…

720全景VR拍摄制作实战教程

720全景VR拍摄制作实战教程 720全景VR拍摄制作是近年来兴起的一种沉浸式影像制作技术。它通过多角度拍摄&#xff0c;并将画面拼接成一个全景视角&#xff0c;使观众获得身临其境的观看体验。本教程将带你从准备阶段到拍摄阶段&#xff0c;再到后期处理阶段&#xff0c;一步步…

什么真正的云原生开发?如何区别本地开发后部署到云端?

以下是关于云原生开发的深度解析&#xff0c;以及与本地开发后迁移上云的本质区别&#xff1a; 一、真正的云原生开发&#xff1a;从理念到实践的全面革新 1. 定义与核心思想 云原生开发是一种以云计算能力为核心的架构设计和开发方法论&#xff0c;其本质是让应用从诞生之初…

从代码学习深度学习 - 词的相似性和类比任务 PyTorch版

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言加载预训练词向量TokenEmbedding 类详解预训练词向量简介 (GloVe)具体含义总结建议应用预训练词向量词相似度knn 函数get_similar_tokens 函数相似词查找示例词类比get_analogy 函数词类比任务…

ubuntu 22.04 安装部署elk(elasticsearch/logstash/kibana) 7.10.0详细教程

安装部署elk7.10.0详细教程 一、安装jdk 11环境二、安装elasticsearch 7.10.0三、安装kibana 7.10.0四、安装logstash 7.10.0五、安装ik7.10.0分词六、开启安全功能1. 开启用户名密码登录2. 开启es安全加密通信3. 开启Kibana安全功能 七、注意事项和常见错误八、其它操作及命令…

技术文章: 基板的吸水率

PCB基板或覆铜板的吸水率是一个重要的性能指标&#xff0c;它衡量了覆铜板在特定条件下&#xff08;通常是浸水后&#xff09;吸收水分的能力&#xff0c;通常用指定条件下吸水后与吸水前相比&#xff0c;质量增加的百分比来表示。当材料暴露扎起在潮湿空气中或浸没在水中时其抵…

九日集训第三天

目录 搜索旋转排序数组 搜索旋转排序数组|| 寻找旋转排序中的数组最小值 爬楼梯 斐波那契数 第N个泰波那契数 差的绝对值为K的数对数目 猜数字 拿硬币 山峰数组的峰顶索引 搜索旋转排序数组 class Solution { public:int search(vector<int>& nums, int t…