SpringBoot配置类

在Spring Boot中,配置类是一种特殊的类,用于定义和配置Spring应用程序的各种组件、服务和属性。这些配置类通常使用Java注解来声明,并且可以通过Spring的依赖注入机制来管理和使用。

Spring 容器初始化时会加载被@Component、@Service、@Repository、@Controller等注解标识的类,除了注解标识的类,Spring容器还会加载配置类中定义的Bean。配置类通常使用@Configuration注解标识,它们中定义的方法会被Spring容器识别为Bean的创建方法。

本篇主要讲 Springboot 配置类一些常见的用法,按照 SpringBoot 加载顺序配置监听器,过滤器,拦截器,定时器以及读取自定义配置文件。

定义配置类

package com.shore.confittestdemo.config;import org.springframework.context.annotation.Configuration;@Configuration
public class MyConfig {}

监听器

`ServletContextListener接口

主要用于监听ServletContext对象的创建和销毁事件。它关注的是Web应用的启动和关闭,以及ServletContext对象的状态变化。

创建一个监听器类,实现ServletContextListener接口

package com.shore.configdemo.config.listener;import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;@WebListener
public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {sce.getServletContext().setAttribute("myApp", "config-demo");System.out.println("MyServletContextListener:监听器启动");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println(sce.getServletContext().getAttribute("myApp"));System.out.println("MyServletContextListener:监听器销毁");}
}

注解 @WebListener 标记为一个监听器类(没啥用)

@Beanpublic ServletContextListener servletContextListener() {return new MyServletContextListener();}

系统启动时上下文添加 app 信息,系统退出时,获取上下文的 app 信息

ApplicationListener‌ 接口

主要用于监听Spring应用生命周期中的事件,如应用启动、上下文刷新、自定义事件等。它关注的是Spring容器内部的事件。

监听上下文刷新事件

创建一个监听器类,实现 ApplicationListener 接口,指定要监听的事件类型,ContextRefreshedEvent 或者 ContextClosedEvent 或者其他自定义类型的事件,重写 onApplicationEvent 方法,编写监听到事件后需要执行的逻辑。

package com.shore.configdemo.config.listener;import jakarta.servlet.annotation.WebListener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@WebListener
//@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("MyApplicationListener: 监听到上下文刷新" + event);}@Overridepublic boolean supportsAsyncExecution() {return ApplicationListener.super.supportsAsyncExecution();}
}

配置类中注册 监听器

@Beanpublic MyApplicationListener listener() {return new MyApplicationListener();}

项目启动创建上下文时被 ServletContextListener 监听到,更新上下文信息,然后被 ApplicationListener 监听器捕获到。

监听上下文刷新和上下文关闭事件

有时候我们希望在一个监听器中监听多个事件,而不是每个事件增加一个监听器类,这时我们可以采用在自定义方法上增加注解 @EventListener,指定要监听的事件类型,一个类中可以有多个注解监听多个事件。

package com.shore.configdemo.config.listener;import jakarta.servlet.annotation.WebListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;@WebListener
public class MyMultiEventListener {@EventListenerpublic void handleContextRefreshEvent(ContextRefreshedEvent event) {System.out.println("MyMultiEventListener.handleContextRefreshEvent:监听到上下文刷新");}@EventListenerpublic void handleContextClosedEvent(ContextClosedEvent event) {System.out.println("MyMultiEventListener.handleContextClosedEvent:监听到上下文关闭");}
}

监听多个自定义事件

实际业务中,我们可能需要监听一些其他的业务,比如类初始化等,可以通过自定义事件来完成。

创建一个类继承 ApplicationEvent 定义一个事件

package com.shore.configdemo.config.event;import org.springframework.context.ApplicationEvent;public class MyCustomEvent extends ApplicationEvent {private String message;public MyCustomEvent(Object source) {super(source);}public MyCustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}

定义一个类,调用 ApplicationEventPublisher 接口发布事件

package com.shore.configdemo.config.publisher;import com.shore.configdemo.config.event.MyCustomEvent;
import jakarta.annotation.Resource;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class MyEventPublisher {@Resourceprivate ApplicationEventPublisher eventPublisher;public void publishEvent() {MyCustomEvent myCustomEvent = new MyCustomEvent(this, "Hello, this is custom event");eventPublisher.publishEvent(myCustomEvent);}
}

在启动类或其他地方调用发布事件方法

package com.shore.configdemo;import com.shore.configdemo.config.publisher.MyEventPublisher;
import jakarta.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ConfigDemoApplication implements CommandLineRunner {@Resourceprivate MyEventPublisher myEventPublisher;public static void main(String[] args) {SpringApplication.run(ConfigDemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {myEventPublisher.publishEvent();}
}

监听自定义事件

@EventListenerpublic void handleMyCustomEvent(MyCustomEvent event) {System.out.println("MyMultiEventListener.handleContextClosedEvent:监听到自定义事件:" + event.getMessage());}

过滤器

Spring Boot 中的过滤器(Filter)主要用于对请求和响应进行预处理或后处理,常用于处理诸如日志记录、身份验证、头信息处理、请求修改等任务。

新建一个过滤器类,继承 javax.servlet.Filter 接口,也可以继承 OncePerRequestFilter 类,它确保在一次请求中只通过一次filter,无需显式检查是否已过滤。

package com.shore.configdemo.config.filter;import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;public class MyCustomFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 过滤器前执行的操作System.out.println("MyCustomFilter: Before doFilter");System.out.println("Request URI: " + request.getRequestURI());System.out.println("Request Method: " + request.getMethod());// 继续过滤器链filterChain.doFilter(request, response);// 过滤器后执行的逻辑System.out.println("MyCustomFilter: After doFilter");System.out.println("Response Status: " + response.getStatus());}
}

在配置类中注册过滤器

@Beanpublic FilterRegistrationBean<MyCustomFilter> myCustomFilter() {FilterRegistrationBean<MyCustomFilter> filterRegistrationBean = new FilterRegistrationBean<>();filterRegistrationBean.setFilter(new MyCustomFilter());// 设置特定过滤路径filterRegistrationBean.addUrlPatterns("/*");// 设置过滤器顺序filterRegistrationBean.setOrder(1);return filterRegistrationBean;}

通过postman 或者 http 请求在配置类中配置范围的控制器

拦截器

Spring Boot 中的拦截器(Interceptor)主要用于拦截和处理 Spring MVC 框架中的 HTTP 请求和响应。与过滤器(Filter)相比,拦截器更侧重于对 Spring MVC 框架内的请求进行处理,例如,处理控制器方法的前后逻辑。

创建一个拦截器类实现 HandlerInterceptor 接口,重写接口的三个方法 preHandlepostHandleafterCompletion,分别用于在请求处理前、请求处理后(但在视图渲染之前)以及整个请求完成后进行拦截。

package com.shore.configdemo.config.interceptor;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class MyCustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在控制器方法执行之前调用System.out.println("MyCustomInterceptor: Pre Handle method is Calling");// 如果返回 false,将中断请求,不会调用后续的拦截器和控制器方法return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在控制器方法执行之后,视图渲染之前调用System.out.println("yCustomInterceptor: Post Handle method is Calling");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在整个请求完成之后调用(包括视图渲染和异常处理)System.out.println("Request and Response is completed");}
}

配置类中注册拦截器,与监听器和过滤器不同,注册拦截器的配置类需要实现 WebMvConfigurer 接口,并重写他的 addInterceptors 方法。

package com.shore.configdemo.config;import com.shore.configdemo.config.filter.MyCustomFilter;
import com.shore.configdemo.config.interceptor.MyCustomInterceptor;
import com.shore.configdemo.config.listener.MyApplicationListener;
import com.shore.configdemo.config.listener.MyMultiEventListener;
import com.shore.configdemo.config.listener.MyServletContextListener;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletContextListener;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MyConfig implements WebMvcConfigurer {@Resourceprivate MyCustomInterceptor myCustomInterceptor;@Beanpublic FilterRegistrationBean<MyCustomFilter> myCustomFilter() {FilterRegistrationBean<MyCustomFilter> filterRegistrationBean = new FilterRegistrationBean<>();filterRegistrationBean.setFilter(new MyCustomFilter());// 设置特定过滤路径filterRegistrationBean.addUrlPatterns("/*");// 设置过滤器顺序filterRegistrationBean.setOrder(1);return filterRegistrationBean;}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myCustomInterceptor).addPathPatterns("/**") // 拦截特定的请求.excludePathPatterns("/login"); // 排除特定的请求}
}

一旦拦截器被注册到 Spring Boot 应用中,它就会自动对匹配的请求起作用。根据你的配置(如路径模式),每次符合条件的请求都会先经过拦截器,然后再继续处理。

我们在控制器新增两个方法,一个 post 方法用来访问,一个 get 方法用来拦截器重定向,拦截器建议重定向 get 方法

package com.shore.configdemo.web;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class MyCustomController {@PostMapping("/sayHello")public String sayHello() {System.out.println("sayHello");return "Hello World";}@GetMapping("/login")public String login() {System.out.println("login");return "login success";}
}

我们来分析以下上图的链路,首先我们调用 sayHllo 方法走到过滤器的链路,打印过滤器链之前的逻辑,然后继续后面的过滤器链,接着请求被拦截器拦截到,执行拦截器 preHandler 方法,该方法 重定向到 login 并结束当前链路,不再访问 sayHello,接着 login 又被过滤器捕获到,执行过滤前逻辑,然后被拦截器放行,访问到 login 接口,正常返回又被过滤器捕获到,执行过滤器后置逻辑,至此链路结束。

我们将拦截器中判断 session 返回 false 的逻辑删掉,重新访问 sayHello,执行一次完整的拦截器逻辑.

这里我们可以看到先走到过滤器前置逻辑,接着拦截器 preHandle 方法,然后走到sayHello 接口,然后走到拦截器 postMethod 方法,然后是拦截器 afterCompletion 方法,最后走到过滤器后值逻辑。

定时器

在Spring Boot中,实现定时器功能通常有几种方法,包括使用@Scheduled注解、TaskScheduler接口以及通过@EnableScheduling和配置类来设定定时任务。

@Scheduled注解

@Scheduled注解提供了最简便的方式来声明定时任务。你只需在相应的方法上添加此注解,并指定相应的cron表达式或其他定时规则。

首先,确保你的Spring Boot应用已经启用了定时任务支持,这通常通过在主应用类或配置类上添加@EnableScheduling注解来实现。

package com.shore.configdemo;import com.shore.configdemo.config.publisher.MyEventPublisher;
import jakarta.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class ConfigDemoApplication implements CommandLineRunner {@Resourceprivate MyEventPublisher myEventPublisher;public static void main(String[] args) {SpringApplication.run(ConfigDemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {myEventPublisher.publishEvent();}
}

创建一个定时任务类,方法使用 @Scheduled 注解标记

package com.shore.configdemo.config.schedule;import org.springframework.scheduling.annotation.Scheduled;import java.util.Date;public class MyCustomScheduleTask {@Scheduled(cron = "0 * * * * *")public void myScheduleTask() {System.out.println("MyCustomScheduleTask: " + new Date());}
}

配置类注册定时任务类

@Beanpublic MyCustomScheduleTask myCustomScheduleTask() {return new MyCustomScheduleTask();}

TaskScheduler接口

如果你需要更细粒度的控制,比如任务池、线程管理等,你可以直接使用TaskScheduler接口。首先,定义一个TaskScheduler的bean

@Beanpublic TaskScheduler taskScheduler() {ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(10);return taskScheduler;}

然后,你可以注入TaskScheduler并使用它来调度任务

package com.shore.configdemo.service.impl;import com.shore.configdemo.service.MyService;
import jakarta.annotation.Resource;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class MyServiceImpl implements MyService {@Resourceprivate TaskScheduler taskScheduler;@Overridepublic void sayHello(String name) {}public void scheduleTask() {taskScheduler.scheduleWithFixedDelay(() -> {System.out.println("执行定时任务: " + new Date());}, 5000); // 任务间隔5秒}
}

@EnableScheduling和配置类

前面已经提到了@EnableScheduling注解,它用于启用Spring的计划任务调度功能。通常,你只需在主应用类或任何配置类上添加此注解,然后就可以在你的应用中使用@Scheduled注解来声明定时任务了。

除了简单的启用定时任务外,你还可以通过实现SchedulingConfigurer接口来自定义定时任务的配置,比如设置任务执行器(TaskExecutor)或任务调度器(TaskScheduler)的属性。

package com.shore.configdemo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;import java.util.Date;@Configuration
@EnableScheduling
public class MyCustomSchedulingTask implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.addTriggerTask(() -> System.out.println("执行基于触发器的任务: " + new Date()),triggerContext -> {// 自定义触发器逻辑,比如根据时间或条件来决定是否执行任务return new CronTrigger("0 * * * * *").nextExecutionTime(triggerContext).toInstant();});}
}

配置文件属性

自定义配置文件 custom-config.yaml

my-app:auth-filter:secretKey: mySecretKeyexpirationTime: 864000000 # 10 天excludes:- /shore/demo/user/login- /shore/demo/user/register- /shore/demo/user/querysnowflake:workerId: 1datacenterId: 1

application.yaml 文件配置自定义配置文件的路径

spring:config:import: classpath:custom-config.yaml

创建配置文件类,指定要读取的标签,定义要读取的属性

package com.shore.my_spring_demo.web.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.List;@ConfigurationProperties(prefix = "my-app.auth-filter")
@Data
public class CustomAuthFilterConfig {private String secretKey;private long expirationTime;private List<String> excludes;
}

配置类中注册配置文件类

@Beanpublic CustomAuthFilterConfig customAuthFilterConfig() throws NoSuchAlgorithmException {return new CustomAuthFilterConfig();}

最后就可以在服务中生命使用了

package com.shore.my_spring_demo.service.jwt;import com.shore.my_spring_demo.common.enums.ErrorEnums;
import com.shore.my_spring_demo.exception.UsersException;
import com.shore.my_spring_demo.web.config.CustomAuthFilterConfig;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.security.KeyPair;
import java.util.Date;@Slf4j
@Service
public class JwtServiceImpl implements JwtService {@Resourceprivate CustomAuthFilterConfig customConfig;@Resourceprivate KeyPair keyPair;@Overridepublic String generateTokenAsymmetric(String username) {return Jwts.builder().claim("sub", username).claim("role", "admin").expiration(new Date(System.currentTimeMillis() + customConfig.getExpirationTime())).signWith(SignatureAlgorithm.RS256, keyPair.getPrivate()).compact();}
}

总结

上述所有在配置类中注册的类,大多都可以直接通过注解 @Compent 标记这种简单的方法进行注册,但是如果想要更加精细化的操作,还是需要在配置类中通过 bean 管理注册。

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

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

相关文章

SpringBoot教程(二十五) | SpringBoot配置多个数据源

SpringBoot教程&#xff08;二十五&#xff09; | SpringBoot配置多个数据源 前言方式一&#xff1a;使用dynamic-datasource-spring-boot-starter引入maven依赖配置数据源动态切换数据源实战 方式二&#xff1a;使用AbstractRoutingDataSource1. 创建数据源枚举类2. 创建数据源…

ZooKeeper单机、集群模式搭建教程

单点配置 ZooKeeper在启动的时候&#xff0c;默认会读取/conf/zoo.cfg配置文件&#xff0c;该文件缺失会报错。因此&#xff0c;我们需要在将容器/conf/挂载出来&#xff0c;在制定的目录下&#xff0c;添加zoo.cfg文件。 zoo.cfg logback.xml 配置文件的信息可以从二进制包…

【大数据学习 | HBASE高级】hbase-phoenix 与二次索引应用

1. hbase-phoenix的应用 1.1 概述&#xff1a; 上面我们学会了hbase的操作和原理&#xff0c;以及外部集成的mr的计算方式&#xff0c;但是我们在使用hbase的时候&#xff0c;有的时候我们要直接操作hbase做部分数据的查询和插入&#xff0c;这种原生的方式操作在工作过程中还…

拆解测试显示Mac Mini (2024)固态硬盘并未锁定 互换硬盘后仍可使用

此前已经有维修达人尝试将 Mac Mini (2024) 固态硬盘上的 NAND 闪存拆下并替换实现扩容&#xff0c;例如可以从 256GB 扩容到 2TB。虽然接口类似于 NVMe M.2 SSD 但直接安装普通硬盘是无效的&#xff0c;苹果仍然通过某种机制检测硬盘是否能够兼容。 不过知名拆解网站 iFixit 的…

主界面获取个人信息客户端方

主界面获取个人信息客户端方 前言 上一集我们完成了websocket身份验证的内容&#xff0c;那么这一集开始我们将要配合MockServer来完成主界面获取个人信息的内容。 需求分析 我们这边是完成客户端那方的内容&#xff0c;当客户端登录成功之后&#xff0c;我们就要从服务器获…

Spring整合Redis

前言 在Spring项目中整合Redis&#xff0c;能显著提升数据缓存、分布式锁、会话管理等操作的效率。Jedis作为轻量级的Java Redis客户端&#xff0c;搭配Spring Data Redis模块&#xff0c;能够简化Redis的连接和数据操作&#xff0c;实现更高性能的读写与灵活的缓存管理。本文…

爬虫——Requests库的使用

在爬虫开发中&#xff0c;HTTP请求是与服务器进行交互的关键操作。通过发送HTTP请求&#xff0c;爬虫可以获取目标网页或接口的数据&#xff0c;而有效地处理请求和响应是爬虫能够高效且稳定运行的基础。Requests库作为Python中最常用的HTTP请求库&#xff0c;因其简洁、易用和…

LinkedHashMap实现LRU

LRU 环境&#xff1a;JDK11 最近接触LRU(Least Recently Used)&#xff0c;即最近最少使用&#xff0c;也称淘汰算法&#xff0c;在JDK中LinkedHashMap有相关实现 LRU的LinkedHashMap实现 LinkedHashMap继承HashMap。所以内存的存储结构和HashMap一样&#xff0c;但是LinkedH…

IDEA部署AI代写插件

前言 Hello大家好&#xff0c;当下是AI盛行的时代&#xff0c;好多好多东西在AI大模型的趋势下都变得非常的简单。 比如之前想画一幅风景画得先去采风&#xff0c;然后写实什么的&#xff0c;现在你只需描述出你想要的效果AI就能够根据你的描述在几分钟之内画出一幅你想要的风景…

27-压力测试

测试目标 & 测试数据 ● 测试目标 ○ 测试集群的读写性能 / 做集群容量规划 ○ 对 ES 配置参数进行修改&#xff0c;评估优化效果 ○ 修改 Mapping 和 Setting&#xff0c;对数据建模进行优化&#xff0c;并测试评估性能改进 ○ 测试 ES 新版本&#xff0c;结合实际场…

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明 文章目录 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明前言1. Ribbon 介绍1.1 LB(Load Balance 负载均衡) 2. Ribbon 原理2.2 Ribbon 机制 3. Spring Cloud Ribbon 实现负载均衡算法-应用实例4. 总结&#x…

vue3【实战】切换全屏【组件封装】FullScreen.vue

效果预览 原理解析 使用 vueUse 里的 useFullscreen() 实现 代码实现 技术方案 vue3 vite UnoCSS vueUse 组件封装 src/components/FullScreen.vue <template><component:is"tag"click"toggle":class"[!isFullscreen ? i-ep:full-sc…

docker:基于Dockerfile镜像制作完整案例

目录 摘要目录结构介绍起始目录package目录target目录sh目录init.sh脚本start.sh脚本stop.sh脚本restart.sh脚本 config目录 步骤1、编写dockerfilescript.sh脚本 2、构件镜像查看镜像 3、保存镜像到本地服务器4、复制镜像文件到指定目录&#xff0c;并执行init.sh脚本5、查看挂…

微澜:用 OceanBase 搭建基于知识图谱的实时资讯流的应用实践

本文作者&#xff1a; 北京深鉴智源科技有限公司架构师 郑荣凯 本文整理自北京深鉴智源科技有限公司架构师郑荣凯&#xff0c;在《深入浅出 OceanBase 第四期》的分享。 知识图谱是一项综合性的系统工程&#xff0c;需要在在各种应用场景中向用户展示经过分页的一度关系。 微…

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…

Mac上详细配置java开发环境和软件(更新中)

文章目录 概要JDK的配置JDK下载安装配置JDK环境变量文件 Idea的安装Mysql安装和配置Navicat Premium16.1安装安装Vscode安装和配置Maven配置本地仓库配置阿里云私服Idea集成Maven 概要 这里使用的是M3型片 14.6版本的Mac 用到的资源放在网盘 链接: https://pan.baidu.com/s/17…

[⑧5G NR]: PBCH payload生成

本篇博客记录下5G PBCH信道中payload数据的生成方式。PBCH payload一共32个比特&#xff0c;基本结构如下图&#xff1a; 根据SSB PDU中bchPayloadFlag的值有三种方式得到PBCH payload。 bchPayloadFlag 0&#xff1a;全部32比特由MAC层提供。 bchPayloadFlag 1&#xff1a;M…

预处理(1)(手绘)

大家好&#xff0c;今天给大家分享一下编译器预处理阶段&#xff0c;那么我们来看看。 上面是一些预处理阶段的知识&#xff0c;那么明天给大家讲讲宏吧。 今天分享就到这里&#xff0c;谢谢大家&#xff01;&#xff01;

EEG+EMG学习系列 (2) :实时 EEG-EMG 人机界面的下肢外骨骼控制系统

[TOC]( EEGEMG学习系列(2):实时 EEG-EMG 人机界面的下肢外骨骼控制系统) 论文地址&#xff1a;https://ieeexplore.ieee.org/abstract/document/9084126 论文题目&#xff1a;Real-Time EEG–EMG Human–Machine Interface-Based Control System for a Lower-Limb Exoskeleton …

用指针遍历数组

#include<stdio.h> int main() {//定义一个二维数组int arr[3][4] {{1,2,3,4},{2,3,4,5},{3,4,5,6},};//获取二维数组的指针int (*p)[4] arr;//二维数组里存的是一维数组int[4]for (int i 0; i < 3; i){//遍历一维数组for (int j 0; j <4; j){printf("%d &…