一文了解Spring提供的几种扩展能力
基于 spring bean 的扩展
1. BeanPostProcessor
spring 提供的针对 bean 的初始化过程时提供的扩展能力,从方法名也很容易看出,提供的两个方法分别是为 bean 对象提供了初始化之前以及初始化之后的扩展能力。
package com.wyl.conf;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
2. InstantiationAwareBeanPostProcessor
package com.wyl.conf;import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {// 相当于new这个bean对象之前return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {// 相当于new这个bean对象之后return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {// 在注入bean对象属性时调用,@Autowired注解就是基于此方法实现的return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 初始化这个bean对象,被spring注入上下文中之前return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 初始化这个bean对象,被spring注入上下文中之后return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
3. InitializingBean
package com.wyl.conf;import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class MyInitializing implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("===MyInitializing===");}
}
4. 初始化器(ApplicationContextInitializer)
向 ConfigurableEnvironment
中注册一些 property sources
或获取 getBeanFactory
来访问容器中的 bean
package com.wyl.initializer;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// environmentConfigurableEnvironment environment = applicationContext.getEnvironment();MutablePropertySources propertySources = environment.getPropertySources();String[] activeProfiles = environment.getActiveProfiles();// beanFactoryapplicationContext.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}});}
}
同样可通过 spring.factories
方式进行注册
org.springframework.context.ApplicationContextInitializer=\
com.wyl.initializer.MyInitializer
5. BeanFactoryPostProcessor
package com.wyl.conf;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("MyBeanFactoryPostProcessor---postProcessBeanFactory");}
}
基于 spring boot 的扩展
1. 监听器(SpringApplicationRunListener)
这是针对 SpringApplication.run
方法执行时提供的一种监听能力,可以在服务启动的多个阶段进行控制。
package com.wyl.listener;import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;public class MyListener implements SpringApplicationRunListener {public MyListener(SpringApplication application, String[] args) {}@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {System.out.println("P1---staring");SpringApplicationRunListener.super.starting(bootstrapContext);}@Overridepublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {System.out.println("P2---environmentPrepared");SpringApplicationRunListener.super.environmentPrepared(bootstrapContext, environment);}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {System.out.println("P3---contextPrepared");SpringApplicationRunListener.super.contextPrepared(context);}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("P4---contextLoaded");SpringApplicationRunListener.super.contextLoaded(context);}@Overridepublic void started(ConfigurableApplicationContext context) {System.out.println("P5---started");SpringApplicationRunListener.super.started(context);}@Overridepublic void running(ConfigurableApplicationContext context) {System.out.println("P6---running");SpringApplicationRunListener.super.running(context);}@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {System.out.println("failed");SpringApplicationRunListener.super.failed(context, exception);}
}
直接通过启动日志的输出位置可直观的看到每个方法的具体扩展点位置。
P1---staring
P2---environmentPrepared. ____ _ __ _ _/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )___ | '_ | '_| | '_ / _` | \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |___, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.4.2)P3---contextPrepared
2023-02-16 18:45:11.748 INFO 12108 --- [ main] com.wyl.MyApplication : Starting MyApplication using Java 17.0.13 on DESKTOP-6O879NM with PID 12108 (D:\learn\hodgepodge\hodgepodge\my-springboot\target\classes started by 26352 in D:\learn\hodgepodge)
2023-02-16 18:45:11.750 INFO 12108 --- [ main] com.wyl.MyApplication : No active profile set, falling back to default profiles: default
P4---contextLoaded
2023-02-16 18:45:12.437 INFO 12108 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-02-16 18:45:12.443 INFO 12108 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-02-16 18:45:12.443 INFO 12108 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
2023-02-16 18:45:12.495 INFO 12108 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-02-16 18:45:12.495 INFO 12108 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 705 ms
2023-02-16 18:45:12.660 INFO 12108 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2023-02-16 18:45:12.721 INFO 12108 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2023-02-16 18:45:12.837 INFO 12108 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-02-16 18:45:12.844 INFO 12108 --- [ main] com.wyl.MyApplication : Started MyApplication in 1.333 seconds (JVM running for 1.799)
P5---started
P6---running
通过写spring.factories
文件的方式注入即可
org.springframework.boot.SpringApplicationRunListener=\
com.wyl.listener.MyListener
2. Runner
也是用于在启动完成后再执行的代码,并且它可以方便的获取启动参数
package com.wyl.runner;import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class MyRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("myRunner");for (String nonOptionArg : args.getNonOptionArgs()) {System.out.println(nonOptionArg);}}
}
P1---staring
P2---environmentPrepared. ____ _ __ _ _/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )___ | '_ | '_| | '_ / _` | \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |___, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.4.2)P3---contextPrepared
2023-02-16 18:45:11.748 INFO 12108 --- [ main] com.wyl.MyApplication : Starting MyApplication using Java 17.0.13 on DESKTOP-6O879NM with PID 12108 (D:\learn\hodgepodge\hodgepodge\my-springboot\target\classes started by 26352 in D:\learn\hodgepodge)
2023-02-16 18:45:11.750 INFO 12108 --- [ main] com.wyl.MyApplication : No active profile set, falling back to default profiles: default
P4---contextLoaded
2023-02-16 18:45:12.437 INFO 12108 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-02-16 18:45:12.443 INFO 12108 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-02-16 18:45:12.443 INFO 12108 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
2023-02-16 18:45:12.495 INFO 12108 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-02-16 18:45:12.495 INFO 12108 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 705 ms
2023-02-16 18:45:12.660 INFO 12108 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2023-02-16 18:45:12.721 INFO 12108 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2023-02-16 18:45:12.837 INFO 12108 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-02-16 18:45:12.844 INFO 12108 --- [ main] com.wyl.MyApplication : Started MyApplication in 1.333 seconds (JVM running for 1.799)
P5---started
myRunner
myarguments=ok
P6---running
3. 自定义 starter
新建一个 module
引入依赖
<dependencies><!-- spring boot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 工具类 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency></dependencies>
在 starter 中我们可以将计数的方法写在一个 service
中
定义个 MethodAccessCounterService
接口
package com.wyl.service;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public interface MethodAccessCounterService {void count(HttpServletRequest request, HttpServletResponse response, Object handler);}
具体实现
package com.wyl.service.impl;import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.wyl.service.MethodAccessCounterService;
import org.springframework.web.method.HandlerMethod;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MethodAccessCounterServiceImpl implements MethodAccessCounterService {private final Table<String, String, Integer> counter = HashBasedTable.create();@Overridepublic void count(HttpServletRequest request, HttpServletResponse response, Object handler) {String remoteAddr = request.getRemoteAddr();if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;String path = handlerMethod.getMethod().getDeclaringClass().getName() + "." + handlerMethod.getMethod().getName();if (counter.contains(path, remoteAddr)) {Integer cnt = counter.get(path, remoteAddr);if (cnt == null) {counter.put(path, remoteAddr, 1);} else {counter.put(path, remoteAddr, cnt + 1);}} else {counter.put(path, remoteAddr, 1);}System.out.println("started提供的方式\t" + remoteAddr + "第" + counter.get(path, remoteAddr) + "次访问:" + path);}}
}
使用自动装配将 MethodAccessCounterServiceImpl
注入到 spring bean
的容器中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wyl.config.MethodAccessCounterConfiguration
package com.wyl.config;import com.wyl.service.MethodAccessCounterService;
import com.wyl.service.impl.MethodAccessCounterServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MethodAccessCounterConfiguration {@Beanpublic MethodAccessCounterService methodAccessCounterService() {return new MethodAccessCounterServiceImpl();}}
再把拦截器配上
package com.wyl.interceptor;import com.wyl.service.MethodAccessCounterService;
import org.springframework.web.servlet.HandlerInterceptor;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MethodAccessCounterInterceptor implements HandlerInterceptor {@Resourceprivate MethodAccessCounterService methodAccessCounterService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {methodAccessCounterService.count(request, response, handler);return true;}
}
package com.wyl.config;import com.wyl.interceptor.MethodAccessCounterInterceptor;
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 WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(methodAccessCounterInterceptor()).addPathPatterns("/**");}@Beanpublic MethodAccessCounterInterceptor methodAccessCounterInterceptor() {return new MethodAccessCounterInterceptor();}}
最后,打个包,给到业务方使用即可!
基于 spring web 的扩展
1. 拦截器(HandlerInterceptor)
包依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency><!-- 工具类 -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId>
</dependency>
新建一个自己的 Interceptor
在 preHandle
方法处,实现对每个 ip 访问每个方法次数的统计
package com.wyl.interceptor;import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MethodAccessCounterInterceptor implements HandlerInterceptor {private final Table<String, String, Integer> counter = HashBasedTable.create();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String remoteAddr = request.getRemoteAddr();if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;String path = handlerMethod.getMethod().getDeclaringClass().getName() + "." + handlerMethod.getMethod().getName();if (counter.contains(path, remoteAddr)) {Integer cnt = counter.get(path, remoteAddr);if (cnt == null) {counter.put(path, remoteAddr, 1);} else {counter.put(path, remoteAddr, cnt + 1);}} else {counter.put(path, remoteAddr, 1);}System.out.println(remoteAddr + "第" + counter.get(path, remoteAddr) + "次访问:" + path);}return true;}
}
将新建的拦截器添加到拦截器链中
package com.wyl.config;import com.wyl.interceptor.MethodAccessCounterInterceptor;
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 WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MethodAccessCounterInterceptor()).addPathPatterns("/**");}
}
测试方法
@Controller
public class TestController {@RequestMapping("/index")public String index() {return "index";}@RequestMapping("/test")public String test() {return "index";}}
测试结果
分别访问:http://localhost:8080/index 与 http://localhost:8080/test 输出的结果如下:
目录结构
基于 spring aop 的扩展
1. aop
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
构建切面,在方式执行之前记录
package com.wyl.aop;import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Component
@Aspect
public class MethodAccessCounterAspect {private final Table<String, String, Integer> counter = HashBasedTable.create();@Before("execution(* com.wyl.controller.*.*(..))")public void before(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs();HttpServletRequest request = null;for (Object arg : args) {if (arg instanceof HttpServletRequest) {request = (HttpServletRequest) arg;break;}}if (request != null) {String remoteAddr = request.getRemoteAddr();String path = joinPoint.getSignature().getDeclaringTypeName() + '.' + joinPoint.getSignature().getName();if (counter.contains(path, remoteAddr)) {Integer cnt = counter.get(path, remoteAddr);if (cnt == null) {counter.put(path, remoteAddr, 1);} else {counter.put(path, remoteAddr, cnt + 1);}} else {counter.put(path, remoteAddr, 1);}System.out.println("使用aop方式\t" + remoteAddr + "第" + counter.get(path, remoteAddr) + "次访问:" + path);}}
}
新增一个测试方法
方法中要传入 HttpServletRequest
否则切面上无法获取到请求 IP
@RequestMapping("/aop")
public String aop(HttpServletRequest request) {return "index";
}
访问:http://localhost:8080/aop 结果如下:
完整时序
服务启动加载时序图
容器环境外执行
SpringApplicationRunListener
提供了多个接口以供使用,其中 starting
方法是最早的执行,此时几乎还没有做任何事情。
environmentPrepared
contextPrepared、contextLoaded 两个方法一前一后都在 prepareContext
方法中被执行
started、running 一目了然,执行到这两个方法时服务已经启动完成了。
ApplicationContextInitializer 是在 refreshContext
方法之前执行的
容器环境内执行
另外几个 InitializingBean、BeanPostProcessor、BeanFactoryPostProcessor、InstantiationAwareBeanPostProcessor、ApplicationContextInitializer 都是在执行 refreshContext
方法时处理,由 org.springframework
包提供。
Bean 实例化与初始化的入口方法整理
实例化前
BeanFactoryPostProcessor -> postProcessBeanFactory
InstantiationAwareBeanPostProcessor -> postProcessBeforeInstantiation
实例化后
InstantiationAwareBeanPostProcessor -> postProcessAfterInstantiation
InstantiationAwareBeanPostProcessor -> postProcessPropertyValues
初始化前
BeanPostProcessor - > postProcessBeforeInitialization
InstantiationAwareBeanPostProcessor - > postProcessBeforeInitialization
初始化后
InitializingBean -> afterPropertiesSet
BeanPostProcessor - > postProcessAfterInitialization
InstantiationAwareBeanPostProcessor - > postProcessAfterInitialization
相关文章:
一文了解Spring提供的几种扩展能力
基于 spring bean 的扩展 1. BeanPostProcessor spring 提供的针对 bean 的初始化过程时提供的扩展能力,从方法名也很容易看出,提供的两个方法分别是为 bean 对象提供了初始化之前以及初始化之后的扩展能力。 package com.wyl.conf;import org.spring…...
VXLAN说明
1. 什么是 VXLAN ? VXLAN(Virtual Extensible LAN,虚拟扩展局域网)是一种网络虚拟化技术,旨在通过在现有的物理网络上实现虚拟网络扩展,从而克服传统 VLAN 的一些限制。 VXLAN 主要用于数据中心、云计算环…...
MyBatis基本使用
一、向SQL语句传参: 1.MyBatis日志输出配置: mybatis配置文件设计标签和顶层结构如下: 可以在mybatis的配置文件使用settings标签设置,输出运过程SQL日志,通过查看日志,可以判定#{}和${}的输出效果 settings设置项: logImpl指定 MyBatis 所用日志的具…...
Linux笔记---进程:进程切换与O(1)调度算法
1. 补充概念 1.1 并行与并发 竞争性:系统进程数目众多,而CPU资源只有少量,甚至只有1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。独立性:多进程运…...
Flink学习连载第二篇-使用flink编写WordCount(多种情况演示)
使用Flink编写代码,步骤非常固定,大概分为以下几步,只要牢牢抓住步骤,基本轻松拿下: 1. env-准备环境 2. source-加载数据 3. transformation-数据处理转换 4. sink-数据输出 5. execute-执行 DataStream API开发 //n…...
[AutoSar]BSW_Diagnostic_007 BootLoader 跳转及APP OR boot response 实现
目录 关键词平台说明背景一、Process Jump to Bootloader二、相关函数和配置2.1 Dcm_GetProgConditions()2.2 Dcm_SetProgConditions() 三、如何实现在APP 还是BOOT 中对10 02服务响应3.1 配置3.2 code 四、报文五、小结 关键词 嵌入式、C语言、autosar、OS、BSW、UDS、diagno…...
用 Python 写了一个天天酷跑(附源码)
Hello,大家好,给大家说一下,我要开始装逼了 这期写个天天酷跑玩一下叭! 制作一个完整的“天天酷跑”游戏涉及很多方面,包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言,…...
WebGL进阶(九)光线
理论基础: 点光源 符合向量定义,末减初。 平行光 环境光 效果: 点光源 平行光 环境光 源码: 点光源 // 顶点着色器程序let vertexstring attribute vec4 a_position; // 顶点位置属性uniform mat4 u_formMatrix; // 用于变换…...
Lucene(2):Springboot整合全文检索引擎TermInSetQuery应用实例附源码
前言 本章代码已分享至Gitee: https://gitee.com/lengcz/springbootlucene01 接上文。Lucene(1):Springboot整合全文检索引擎Lucene常规入门附源码 如何在指定范围内查询。从lucene 7 开始,filter 被弃用,导致无法进行调节过滤。 TermInSetQuery 指定…...
HarmonyOS(57) UI性能优化
性能优化是APP开发绕不过的话题,那么在HarmonyOS开发过程中怎么进行性能优化呢?今天就来总结下相关知识点。 UI性能优化 1、避免在组件的生命周期内执行高耗时操作2、合理使用ResourceManager3、优先使用Builder方法代替自定义组件4、参考资料 1、避免在…...
机器学习周志华学习笔记-第5章<神经网络>
机器学习周志华学习笔记-第5章<神经网络> 卷王,请看目录 5模型的评估与选择5.1 神经元模型5.2 感知机与多层网络5.3 BP(误逆差)神经网络算法 5.4常见的神经网络5.4.1 RBF网络(Radial Basis Function Network,径向基函数网络࿰…...
SQL进阶技巧:如何进行数字范围统计?| 货场剩余货位的统计查询方法
目录 0 场景描述 1 剩余空位区间和剩余空位编号统计分析 2 查找已用货位区间 3 小结 0 场景描述 这是在做一个大型货场租赁系统时遇到的问题,在计算货场剩余存储空间时,不仅仅需要知道哪些货位是空闲的,还要能够判断出哪些货位之间是连续的。因为在新货物入场时,可…...
Xilinx IP核(3)XADC IP核
文章目录 1. XADC介绍2.输入要求3.输出4.XADC IP核使用5.传送门 1. XADC介绍 xadc在 所有的7系列器件上都有支持,通过将高质量模拟模块与可编程逻辑的灵活性相结合,可以为各种应用打造定制的模拟接口,XADC 包括双 12 位、每秒 1 兆样本 (MSP…...
现代大数据架构设计与实践:从数据存储到处理的全面解读
1. 引言 随着信息技术的不断发展,数据已经成为企业和组织最宝贵的资产之一。大数据的应用已经渗透到各个行业,无论是电商、金融,还是医疗、物流,如何有效管理、存储和处理海量的数据已经成为企业成功的关键之一。本文将深入探讨现代大数据架构的设计理念与技术实践,从数据…...
详细教程-Linux上安装单机版的Hadoop
1、上传Hadoop安装包至linux并解压 tar -zxvf hadoop-2.6.0-cdh5.15.2.tar.gz 安装包: 链接:https://pan.baidu.com/s/1u59OLTJctKmm9YVWr_F-Cg 提取码:0pfj 2、配置免密码登录 生成秘钥: ssh-keygen -t rsa -P 将秘钥写入认…...
前端项目支持tailwindcss写样式
安装 npm install -D tailwindcss npx tailwindcss init配置 tailwind.config.js //根据个人需求填写,比如vue简单配置 /** type {import(tailwindcss).Config} */ module.exports {darkMode: "class",corePlugins: {preflight: false},content: [&quo…...
工程师 - 智能家居方案介绍
1. 智能家居硬件方案概述 智能家居硬件方案是实现家庭自动化的重要组件,通过集成各种设备来提升生活的便利性、安全性和效率。这些方案通常结合了物联网技术,为用户提供智能化、自动化的生活体验。硬件方案的选择直接影响到智能家居系统的性能、兼容性、…...
H.264/H.265播放器EasyPlayer.js网页全终端安防视频流媒体播放器关于iOS不能系统全屏
在数字化时代,流媒体播放器已成为信息传播和娱乐消遣的主流载体。随着技术的进步,流媒体播放器的核心技术和发展趋势不断演变,影响着整个行业的发展方向。 EasyPlayer播放器属于一款高效、精炼、稳定且免费的流媒体播放器,可支持…...
2.langchain中的prompt模板 (FewShotPromptTemplate)
本教程将介绍如何使用 LangChain 库中的 PromptTemplate 和 FewShotPromptTemplate 来构建和运行提示(prompt),并通过示例数据展示其应用。 安装依赖 首先,确保你已经安装了 langchain 和相关依赖: pip install lan…...
TCP/IP
1、浏览器输入网址后发生了什么 1)应用层:浏览器解析ULR,生成发送给web服务器的请求信息,HTTP请求报文生成,委托给操作系统将消息发送给web服务器,发送之前需要查询服务器域名对应的IP地址(需要…...
详细探索xinput1_3.dll:功能、问题与xinput1_3.dll丢失的解决方案
本文旨在深入探讨xinput1_3.dll这一动态链接库文件。首先介绍其在计算机系统中的功能和作用,特别是在游戏和输入设备交互方面的重要性。然后分析在使用过程中可能出现的诸如文件丢失、版本不兼容等问题,并提出相应的解决方案,包括重新安装相关…...
Spring:AOP切入点表达式
对于AOP中切入点表达式,我们总共会学习三个内容,分别是语法格式、通配符和书写技巧。 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法切入点表达式:要进行增强的方法的描述方式 对于切入点的描述,我们其实是有两中方式的&a…...
STM32的中断(什么是外部中断和其他中断以及中断号是什么)
一、什么是EXTI 和NVIC EXTI(External Interrupt/Event Controller)EXTI 是外部中断/事件控制器,它负责处理外部信号变化,并将信号传递给中断控制器(如 NVIC)。主要负责以下功能: 外部事件检测…...
MySQL底层概述—1.InnoDB内存结构
大纲 1.InnoDB引擎架构 2.Buffer Pool 3.Page管理机制之Page页分类 4.Page管理机制之Page页管理 5.Change Buffer 6.Log Buffer 1.InnoDB引擎架构 (1)InnoDB引擎架构图 (2)InnoDB内存结构 (1)InnoDB引擎架构图 下面是InnoDB引擎架构图,主要分为内存结构和磁…...
Linux 下进程基本概念与状态
文章目录 一、进程的定义二、 描述进程-PCBtask_ struct内容分类 三、 进程状态 一、进程的定义 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。广义定义:进程是一个具有一定…...
Go语言链接Redis数据库
1.使用go get命令安装go-redis/v8库: 我这里使用的vscode工具安装: go get github.com/go-redis/redis/v82.创建Redis客户端实例 使用以下Go代码连接到Redis服务器并执行命令: package mainimport ("context""fmt"&q…...
SQL 分页查询详解
在处理大型数据集时,分页查询是一种常见的技术,用于将数据分成多个小块,以便逐步加载和显示。这不仅可以提高应用的性能,还可以提升用户体验,避免一次性加载过多数据导致页面加载缓慢或资源消耗过大。本文将详细介绍 S…...
ACP科普:风险价值矩阵
风险价值矩阵(Risk-Value Matrix)是一种常用的工具,用于在项目管理中帮助团队识别、评估和优先处理风险。它通过将风险和价值两个因素进行结合,帮助决策者明确哪些风险需要优先关注和处理,从而有效地管理项目的不确定性…...
计算机网络socket编程(2)_UDP网络编程实现网络字典
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨…...
(Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容
参考 MDK-ARM各种优化选项详细说明、实际应用及拓展内容 本文围绕MDK-ARM优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你今后开发项目有所帮助。 1 总述 我们所指的优化,主要两方面: 1.代码大小(Size) 2.代码性能(运行时间) 在MDK-ARM中,优…...
mac2024 安装node和vue
以下是使用 Node.js 官方 .pkg 安装包 安装 Node.js 和 Vue CLI 的完整流程,包括如何重新设置 npm 的环境,以避免权限问题。 安装 Node.js 步骤 1.1:下载 Node.js 安装包 1. 打开 Node.js 官网。 2. 下载 LTS(长期支持…...
在win10环境部署opengauss数据库(包含各种可能遇到的问题解决)
适用于windows环境下通过docker desktop实现opengauss部署,请审题。 文章目录 前言一、部署适合deskdocker的环境二、安装opengauss数据库1.配置docker镜像源2.拉取镜像源 总结 前言 注意事项:后面docker拉取镜像源最好电脑有科学上网工具如果没有科学上…...
Docker1:认识docker、在Linux中安装docker
欢迎来到“雪碧聊技术”CSDN博客! 在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将…...
鸿蒙开发-音视频
Media Kit 特点 一般场合的音视频处理,可以直接使用系统集成的Video组件,不过外观和功能自定义程度低Media kit:轻量媒体引擎,系统资源占用低支持音视频播放/录制,pipeline灵活拼装,插件化扩展source/demu…...
Vue3学习笔记
目录 Vue3Vue3优势Vue3组合式API & Vue2选项式APIcreate-vue使用create-vue创建项目 项目目录和关键文件组合式API-setup选项组合式API-reactive和ref函数reactive()ref() 组合式API-computed组合式API-watch基础使用immdiate和deep配置精确侦听对象的某个属性 组合式API-生…...
node + Redis + svg-captcha 实现验证码
目录 前提说明 Redis链接与封装 svg-captcha使用步骤 封装中间件验证 前端接收 扩展【svg API】 svgCaptcha.create(options) svgCaptcha.createMathExpr(options) svgCaptcha.loadFont(url) svgCaptcha.options svgCaptcha.randomText([size|options]) svgCaptcha(…...
dubbo-go框架介绍
框架介绍 什么是 dubbo-go Dubbo-go 是 Apache Dubbo 的 go 语言实现,它完全遵循 Apache Dubbo 设计原则与目标,是 go 语言领域的一款优秀微服务开发框架。dubbo-go 提供: API 与 RPC 协议:帮助解决组件之间的 RPC 通信问题&am…...
玛哈特矫平机:工业制造中的平整利器
在日新月异的工业制造领域,每一个细节都至关重要。而在这其中,矫平机以其独特的功能和卓越的性能,成为了不可或缺的重要工具。它就像一位技艺高超的工匠,精心雕琢着每一件工业产品,赋予它们平整、光滑的表面。 矫平机…...
IDEA 2024安装指南(含安装包以及使用说明 cannot collect jvm options 问题 四)
汉化 setting 中选择插件 完成 安装出现问题 1.可能是因为之前下载过的idea,找到连接中 文件,卸载即可。...
Jmeter中的定时器
4)定时器 1--固定定时器 功能特点 固定延迟:在每个请求之间添加固定的延迟时间。精确控制:可以精确控制请求的发送频率。简单易用:配置简单,易于理解和使用。 配置步骤 添加固定定时器 右键点击需要添加定时器的请求…...
共享单车管理系统项目学习实战
前言 Spring Boot Vue前后端分离 前端:Vue(CDN) Element axios(前后端交互) BaiDuMap ECharts(图表展示) 后端:Spring Boot Spring MVC(Web) MyBatis Plus(数据库) 数据库:MySQL 验证码请求 git提交 cd C:/Users/Ustini…...
学Linux的第九天--磁盘管理
目录 一、磁盘简介 (一)、认知磁盘 (1)结构 (2)物理设备的命名规则 (二)、磁盘分区方式 MBR分区 MBR分区类型 扩展 GPT格式 lsblk命令 使用fdisk管理分区 使用gdisk管理分…...
CLIP-Adapter: Better Vision-Language Models with Feature Adapters 论文解读
abstract 大规模对比视觉-语言预训练在视觉表示学习方面取得了显著进展。与传统的通过固定一组离散标签训练的视觉系统不同,(Radford et al., 2021) 引入了一种新范式,该范式在开放词汇环境中直接学习将图像与原始文本对齐。在下游任务中,通…...
D74【 python 接口自动化学习】- python 基础之HTTP
day74 http基础定义 学习日期:20241120 学习目标:http定义及实战 -- http基础介绍 学习笔记: HTTP定义 HTTP 是一个协议(服务器传输超文本到浏览器的传送协议),是基于 TCP/IP 通信协议来传递数据&…...
维护表空间和数据文件(一)
学习目标 定义表空间和数据文件的用途创建表空间管理表空间使用Oracle管理文件(OMF)创建和管理表空间获取表空间信息 表空间和数据文件 Oracle逻辑上将数据存储在表空间中,物理上将数据存储在数据文件中。 Tablespaces: 一次只…...
H.265流媒体播放器EasyPlayer.js H5流媒体播放器关于如何查看手机端的日志信息并保存下来
现今流媒体播放器的发展趋势将更加多元化和个性化。人工智能的应用将深入内容创作、用户体验优化等多个方面,带来前所未有的个性化体验。 EasyPlayer.js H.265流媒体播放器属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放&#…...
Apple Vision Pro开发003-PolySpatial2.0新建项目
unity6.0下载链接:Unity 实时开发平台 | 3D、2D、VR 和 AR 引擎 一、新建项目 二、导入开发包 com.unity.polyspatial.visionos 输入版本号 2.0.4 com.unity.polyspatial(单独导入),或者直接安装 三、对应设置 其他的操作与之前的版本相同…...
解决 npm xxx was blocked, reason: xx bad guy, steal env and delete files
问题复现 今天一位朋友说,vue2的老项目安装不老依赖,报错内容如下: npm install 451 Unavailable For Legal Reasons - GET https://registry.npmmirror.com/vab-count - [UNAVAILABLE_FOR_LEGAL_REASONS] vab-count was blocked, reas…...
leetcode 面试150之 156.LUR 缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -…...
Vue 动态给 data 添加新属性深度解析:问题、原理与解决方案
在 Vue 中,动态地向 data 中添加新的属性是一个常见的需求,但它也可能引发一些问题,尤其是关于 响应式更新 和 数据绑定 的问题。Vue 的响应式系统通过 getter 和 setter 来追踪和更新数据,但 动态添加新属性 时,Vue 并不会自动为这些新属性创建响应式链接。 1. 直接向 V…...