Spring-动态替换Bean

Spring-动态替换Bean 问题 假如spring-boot项目引用了第三方库, 里面有个类通过autowire引用了:testService, 如何修改testService里面的实现逻辑呢? 通过动态替换testService为自定义的bean可以实现这个功能 实现原理 添加一个新的TestService2与原testService实现同样的接口 添加一个组件实现: BeanDefinitionRegistryPostProcessor 使用BeanDefinitionRegistry动态替换bean 代码示例 @Component public class MyBeanProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { final String beanName = "testService"; if (registry.containsBeanDefinition(beanName)) { registry.removeBeanDefinition(beanName); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(TestService2.class); registry.registerBeanDefinition(beanName, beanDefinition); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { } }

January 5, 2023 · FXIO

postman接口签名

后端接口为了安全考虑, 通常会增加接口参数签名认证;增加接口参数签名认证, postman直接调用,会认证失败, 需要实现一套和前端项目一样的签名动作; api参数签名认证api参数签名认证原理 api-time: 本次API调用的有效时间,超过该时间调用失效,避免重放攻击 api-key: 与api-secret是一个pair对,一一对应,知道了api-key即可查询到api-secret api-signature: api-secret和message一起生成的签名,这里的message一般包括api-key, 请求方法, get, post参数 api-signature的生成规则一般为: crypto-js的hmac_sha256,输出值需转化为base64字符串 postman pre-request签名计算 var apiKey = pm.globals.get("apiKey"); var apiSecret = pm.globals.get("apiSecret"); const query = pm.request.url.query; var keys = []; var map = {}; query?.each(e => { let disabled = e["disabled"]; if (!disabled) { let k = e["key"]; keys.push(k); map[k] = e["value"]; } }); const queryArr = []; keys.sort(); keys.forEach(k => { queryArr.push(k + "=" + map[k]); }); const queryStr = queryArr.join("&"); const body = JSON.stringify(JSON.parse(pm.request.body.raw.toString())); var method = request.method; var signArr = [apiKey, method.toLowerCase(), queryStr, body]; const signSrcStr = signArr.join('&'); console.log(signSrcStr); var signatureBase64 = CryptoJS.HmacSHA256(signSrcStr, apiSecret).toString(CryptoJS.enc.Base64); console.log("signatureBase64", signatureBase64); pm.environment.set("api-signature", signatureBase64); const timeStr = Math.round(new Date().getTime()); pm.environment.set("api-time", timeStr); pm.request.body = body; java后端签名计算 class ApiPreHandler { public static String generateHmac256(String msg, String key) { if (Objects.isNull(msg)) { return ""; } if (Objects.isNull(key)) { return msg; } final String algorithm = "HmacSHA256"; try { SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm); Mac mac = Mac.getInstance(algorithm); mac.init(secretKeySpec); byte[] bytes = mac.doFinal(msg.getBytes()); return Base64.getEncoder().encodeToString(bytes); } catch (Exception e) { LogUtils.error(e.getMessage(), e); return ""; } } public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI = request.getRequestURI(); String method = request.getMethod().toLowerCase(Locale.ROOT); String querySorted = getSortedQuery(request.getQueryString()); String body = request.getReader().lines().collect(Collectors.joining()); String apiSignature = request.getHeader("api-signature"); String signStrSrc = String.join("&", Lists.newArrayList(apiKey, method, querySorted, body)); log.info("requestURI: {}, singStrSrc={}", requestURI, signStrSrc); String calcSign = SecurityUtils.generateHmac256(signStrSrc, apiSecret); if (!Objects.equals(apiSignature, calcSign)) { log.error("api-signature denied, signStrSrc={}", signStrSrc); return false; } return true; } }

January 4, 2023 · FXIO

Android录制Gif

有时候我们需要录制Android手机的屏幕,比如写了一个Demo应用,需要发布到博客和微博上。 对于Android4.4以上的手机,系统自带了一个命令screenrecord,我们可以很方便的使用。 录制命令 adb shell screenrecord /sdcard/test.mp4 视频保存目录可以自己指定,如上面的/sdcard/test.mp4, 命令执行后会一直录制180s,按下ctrl+c可以提前结束录制 设定视频分辨率 对于高分辨率的手机,录制的视频很大,我们分享又不需要这么大的 我们可以设置录制的视频分辨率 adb shell screenrecord --size 848x480 /sdcard/test.mp4 设定视频比特率 默认比特率是4M/s,为了分享方便,我们可以调低比特率为2M adb shell screenrecord --bit-rate 2000000 /sdcard/test.mp4 获取视频文件 使用adb pull 即可把手机SD卡中视频获取到本地 adb pull /sdcard/test.mp4 . 转GIF文件 在Windows下有个不错的软件Free Video to GIF Converter可以把mp4转换成GIF。 转换时还可以删除不需要的帧,这点真得很不错。 Mac上可以使用gifrocket进行转换。 原文链接

May 1, 2018 · FXIO

常用的 Linux 命令

常用 Linux 命令 cd 改变当前目录 # 跳转到家目录 cd ~ # 跳转到上级目录 cd .. # 跳转根目录 cd / # 显示当前目录 pwd cp 复制文件 # 复制目录 cp -r source_dir destination_dir mkdir mkdir -p /data/www/test tar tar -zcvf /data/backup/test.tar.gz /data/www/test 系统信息 uname -a cat /proc/cpuinfo cat /proc/meminfo cat /proc/meminfo | grep MemTotal lspci -tv lsusb -tv free -m df -h du -sh /data/www/test uptime fdisk -l 网络 ifconfig netstat -antp netstat -antp | grep 80 进程 ps -ef | grep java # 用户登录日志 last 软件 # 查看已安装的java版本 dpkg -l | grep java # 安装java sudo apt install -y openjdk-8-jdk # 卸载java sudo apt remove openjdk-8-jdk # dpkg -ivh 安装软件包 # rpm -qa | grep java 磁盘容量报警 服务器不停的运行,会产生很多日志文件(nginx,tomcat) 设查询条件为: ...

April 24, 2017 · FXIO

Android-opencv-cmake

Android-opencv-cmake Android opencv image process samples ,build with cmake 环境要求 Android studio 2.3.3 Cmake ndk14 opencv2.4.13 or opencv3.3 配置 在local.properties 文件中配置opencv sdk 路径 opencv.dir = ${opencv_sdk_dir} ndk.dir=/Users/king/Library/Android/ndk14 sdk.dir=/Users/king/Library/Android/sdk opencv.dir=/Users/king/Libs/OpenCV2413 在build.gradle中配置cmake参数 externalNativeBuild { cmake { cppFlags "-std=c++11 -frtti -fexceptions" arguments "-DOpenCV_DIR=" + getOpenCVDir().toString()+"/sdk/native/jni", "-DANDROID_ARM_NEON=TRUE" } } ndk { abiFilters "armeabi-v7a" //, "arm64-v8a","armeabi", } ... def getOpenCVDir() { Properties properties = new Properties() properties.load(new File(rootDir.absolutePath + "/local.properties").newDataInputStream()) def externalModuleDir = properties.getProperty('opencv.dir', null) if (externalModuleDir == null) { throw new GradleException( "OpenCV location not found. Define location with opencv.dir in the local.properties file!") } return externalModuleDir } 项目地址 源码

March 15, 2017 · FXIO

Android OpenCV CMake 调优

AIDL是什么 ? AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互 为什么要有aidl ? 用于两个App之间交换数据的场景 为什么不能直接通讯? 在 Android 上,一个进程通常无法访问另一个进程的内存, 而AIDL只是Android中众多进程间通讯方式中的一种方式 使用方法 服务端AidlApp1 使用Android Studio在Service服务端创建aidl文件: IUserAidlInterface, 然后build一下 package com.joshkryo.aidl; interface IUserAidlInterface { String getUserInfo(int uid); } 创建Service实现类 public class UserAidlService extends Service { private static final String TAG = "UserAidlService"; @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: " + intent); return mBinder; } private final IUserAidlInterface.Stub mBinder = new IUserAidlInterface.Stub() { @Override public String getUserInfo(int uid) throws RemoteException { return "{\"id\":" + uid + " ,name\":\"Tom\",\"age\":18}"; } }; } 注册Service <service android:name="com.joshkryo.aidlapp1.service.UserAidlService" android:enabled="true"> <intent-filter> <action android:name="com.joshkryo.aidlapp1.service.UserAidlService"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service> 客户端AidlApp2 复制AidlApp1的aidl文件到AidlApp2, build一下 bindService class BindService { private void bindAidlService() { Intent intent = new Intent("com.joshkryo.aidlapp1.service.UserAidlService");// service配置的action intent.setPackage("com.joshkryo.aidlapp1");//service服务端包名 bindService(intent, mAidlConn, Context.BIND_AUTO_CREATE); } private ServiceConnection mAidlConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected"); userAidlInterface = IUserAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "onServiceDisconnected: "); userAidlInterface = null; } }; } 使用aidl interface调用AidlApp1里的service class Test { public void getAidlUserInfo(View v) { try { if (userAidlInterface == null) { Log.e(TAG, "onClick: null userAidlInterface instance"); return; } Toast.makeText(MainActivity.this, userAidlInterface.getUserInfo(1), Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } } 可能的错误 Service Intent must be explicit java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.joshkryo.aidlapp1 } at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2854) 原因: Android5.0之后service的intent一定要显性声明 onServiceConnected不调用 可能原因: service 没有在manifest里面注册 服务端, 客户端的 intent action 不一致

March 15, 2017 · FXIO