why为了减少日志文件的数量, 生产环境的日志等级都是 Error, 但是当遇到问题时, 错误日志可能不能快速准确的定位出错的地方, 如果能在不重启应用的情况下,修改日志级别并且生效, 能更快的发现出错的地方. what这里选择使用 JMX 来实现日志级别动态修改. JMX (Java Management Extensions) 是管理 Java 的一种扩展. 这种机制可以方便的管理, 监控正在运行中的 Java 程序. 常用于管理线程, 内存, 日志Level, 服务重启, 系统环境等. 实现一个被 JMX 托管的 MBean 的方式: MBean 的接口必须以 MBean 结尾, 比如 XxxxMBean 实现必须以 Xxxx 命名因为接口定义是 XxxxMBean logback 定义的 MBean jconsole 查看 MBean how动态修改日志级别的思路: API 调用 DynamicChangeLogLevel 修改日志级别 DynamicChangeLogLevel 通过 LogBackMBean 修改日志级别 使用责任链, 修改 xxx-ap ...
代码织入实现方式: 静态代理 AspectJ 织入器 weaver) compile-time weaving 使用 aspectj 编译器进行编译源码 post-compile weaving 对 class 文件进行织入 load-time weaving(LTW) 当 class loader 加载类的时候,进行织入 动态代理 JDK 动态代理 (接口) CGlib(类) 这里使用 AspectJ LTW 实现, 这种方式在类加载器织入代码. 编译器织入 会造成编译速度变慢, 而且必须使用 ajc 编译器 动态代理 会生成大量代理类, 加速内存消耗 因此使用 类加载期织入 相对于其他两种方式, 更加轻便. LTW(Load Time Weaver),即加载期切面织入,是 ApsectJ 切面织入的一种方式,它通过 JVM 代理在类加载期替换字节码到达织入切面的目的。 具体实现首先定义个切面类,该切面功能非常简单,就是在 com.xxx.server.rest.resource.impl 及其所有子包下所有的类的 public 方法调用后打印执行时间 1 ...
使用 Redis Sentinel 重构现有架构 对于搭建高可用 Redis 服务,网上已有了很多方案,例如 Keepalived,Codis,Twemproxy,Redis Sentinel。其中 Codis 和 Twemproxy 主要是用于大规模的 Redis 集群中,也是在 Redis 官方发布 Redis Sentinel 之前 豌豆荚 和 twitter 提供的开源解决方案。Redis Sentinel 可以理解为一个监控 Redis Server 服务是否正常的进程,并且一旦检测到不正常,可以自动地将备份 (slave)Redis Server 启用,使得外部用户对Redis 服务内部出现的异常无感知。 原有架构 存在的问题 配置部署复杂 不稳定 Redis Sentinel 高可用 下面以 1 个主节点、2 个从节点、3 个 Sentinel 节点组成的 Redis Sentinel 为例子 故障转移处理逻辑: 主节点出现故障, 此时两个从节点与主节点时区连接, 主从复制失败; 每个 Sentinel 节点通过定期监控发现主节点出现故障; 多个 ...
Jar 包冲突是老生常谈的问题,几乎每一个 Java 程序猿都不可避免地遇到过,并且也都能想到通常的原因一般是同一个 Jar 包由于 maven 传递依赖等原因被引进了多个不同的版本而导致,可采用依赖排除、依赖管理等常规方式来尝试解决该问题,但这些方式真正能彻底解决该冲突问题吗?答案是否定的。笔者之所以将文章题目起为 “重新看待”,是因为之前对于 Jar 包冲突问题的理解仅仅停留在前面所说的那些,直到在工作中遇到的一系列 Jar 包冲突问题后,才发现并不是那么简单,对该问题有了重新的认识,接下来本文将围绕 Jar 包冲突的问题本质和相关的解决方案这两个点进行阐述。 Jar 包冲突问题一、冲突的本质Jar 包冲突的本质是什么?Google 了半天也没找到一个让人满意的完整定义。其实,我们可以从 Jar 包冲突产生的结果来总结,在这里给出如下定义(此处如有不妥,欢迎拍砖 -): Java 应用程序因某种因素,加载不到正确的类而导致其行为跟预期不一致。 具体来说可分为两种情况:1)应用程序依赖的同一个 Jar 包出现了多个不同版本,并选择了错误的版本而导致 JVM 加载不到需要 ...
新时代码农
未读整理一下项目中不好的代码写法 以下是一些具有代表性的问题, 都是一些一看就明白的问题, 还有一些代码的坑, 慢慢填吧. 只针对代码, 不针对谁, 如果写的不对的对方, 你咬我啊 代码问题还失败重试? 失败重试个啥? 直接返回了 老铁!!代码 1 后面, 获取了 batchResult, 不应该重新赋值 code 嘛? 代码 2 为修改后 Intellij idea 是个好东西 修改为: catch 里面使用 printStackTrace(), 错误日志全部输出到 catalina.out, 你考虑过 catalina 的感受吗? 日志问题后面说 这是先斩后奏吗?前面都调用了 list 的 size 方法, 后面再来判断 list 是否为 null? 这种代码我看见起码不下 10 处, 系统能稳定吗老铁? idea 都知道的问题, 你不应该不知道 logger.info 输出问题: 用 log.info("{}", xxxx), 不要自己拼接字符串 老铁, 你可长点心吧 老铁, 我就服你 google : logger.erro ...
新时代码农
未读项目重构整理 废话此篇是 12530 架构重构第二篇, 以 阿里巴巴开发手册 为基础, 结合自己工作经验, 作为 musicsearch-project重构方案的基础部分.以此为约束, 希望构建一个 稳定, 易于维护, 可扩展 的重构方案. 一个项目最怕多种编码风格, 实体名一会 entity, 一会 model, 让维护的人身心疲惫, 因此在一个项目中保持唯一一种编码习惯, 有利于代码维护 (比如通过命名,就知道作用以及所在的包名). 见名知意, 此乃命名的最高境界 (体会一下 取名 10 分钟, 编码 1 分钟 的境界 😂). 代码规范看起来比较枯燥, 看完一遍可能只有一点点印象, 因此我采用比较逗比的方式, 尽量让大家一遍就记住.代码规范比较偏向个人主义, 每个人的编码习惯都不一样, 所以希望多提出自己的建议, 一起改进 (没有最好的规范, 只有最合适的. 🙃) Let’s go开篇话说盘古开天辟地之时… 亚当和夏娃诞生混沌之间, 他们从小青梅竹马, 一个会唱 200 首歌, 一个会跳 200 支舞, 后人称他们一个为 二百歌, 一个为二百舞 ….. (用心去 ...
记录 Redis Sentinel 的搭建过程 现有架构的问题 master 挂掉之后, 需要手动切换, 运维复杂 Redis Sentinel 高可用 下面以 1 个主节点、2 个从节点、3 个 Sentinel 节点组成的 Redis Sentinel 为例子 故障转移处理逻辑: 主节点出现故障, 此时两个从节点与主节点时区连接, 主从复制失败; 每个 Sentinel 节点通过定期监控发现主节点出现故障; 多个 Sentinel 节点对主节点的故障达成一致, 选举出 sentinel-3 节点作为领导者负责故障转移; 原来的从节点 slave-1 称为新的主节点后, 更新应用方的主节点信息, 重新启动应用方; 客户端命令另一个从节点 slave-2 去复制性的主节点; 待原来的主节点恢复后, 让它去复制新的主节点; 故障转移后的结构图 Redis Sentinel 功能 监控: Sentinel 节点会定期检测 Redis 数据节点和其余 Sentinel 节点是否可达; 通知: Sentinel 节点会将故障转移的结果通知给应用方; 主节点故障转 ...
最近在使用 Spingboot 做项目的时候,在引入 shiro 后,启动项目一直报错 1Error creating bean with name 'debtServiceImpl': Bean with name 'debtServiceImpl' has been injected into other beans [repayBillServiceImpl,investServiceImpl,receiveBillServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOf ...
SSH(Secure Shell)是什么?是一项创建在应用层和传输层基础上的安全协议, 为计算机上的 Shell(壳层)提供安全的传输和使用环境.也是专为远程登录会话和其他网络服务提供安全性的协议.它能够有效防止远程管理过程中的信息泄露问题.通过 SSH 可以对所有传输的数据进行加密, 也能够防止 DNS 欺骗和 IP 欺骗. 具体生成 SSH Key 方式请参考: Github ssh key 生成, 免密登录服务器方法.这里以 id_ecdsa(私钥) 和 id_ecdsa.pub(公钥) 为例. 本篇文章主要介绍 SSH 相关的使用技巧. 通过对 ~/.ssh/config 文件的配置你可以大大简化 SSH 相关的操作, 如: 12345Host example # 关键词 HostName example.com # 主机地址 User root # 用户名 # IdentityFile ~/.ssh/id_ecdsa # 认证文件 # ...
内存优化对比数据量 外呼名单 10 万白名单 100 万黑名单 500 万 JVM 参数 12345678-verbose:gc-XX:+HeapDumpOnOutOfMemoryError-server-Xms1g-Xmx1g-XX:PermSize=512m-XX:SurvivorRatio=2-XX:+UseParallelGC 优化之前对比耗时 1234567891011122018-05-31 15:29:49 [INFO]] [pool-1-thread-1] [parseRegulation] 白名单匹配个数 = 252018-05-31 15:29:50 [INFO]] [pool-1-thread-1] [parseRegulation] 黑名单匹配个数 = 189StopWatch '': running time (millis) = 906-----------------------------------------ms % Task name--------------------------------- ...
文/LNAmp(简书作者)原文链接: http://www.jianshu.com/p/80c7777d48ad 解决方案演化这个问题的技术点在于能够触发重试, 以及重试情况下逻辑有效执行. 解决方案一: try-catch-redo 简单重试模式包装正常上传逻辑基础上, 通过判断返回结果或监听异常决策是否重试, 同时为了解决立即重试的无效执行 (假设异常是有外部执行不稳定导致的),休眠一定延迟时间重新执行功能逻辑. 1234567891011121314151617public void commonRetry(Map<String, Object> dataMap) throws InterruptedException { Map<String, Object> paramMap = Maps.newHashMap(); paramMap.put("tableName", "creativeTable"); paramMap.put("ds", "20 ...
fat jartomcat自定义打包部署 暴露配置文件和静态资源文件前言SpringBoot 默认有 2 种打包方式,一种是直接打成 jar 包,直接使用 java -jar 跑起来,另一种是打成 war 包,移除掉 web starter 里的容器依赖,然后丢到外部容器跑起来。 第一种方式的缺点是整个项目作为一个 jar,部署到生产环境中一旦有配置文件需要修改,则过程比较麻烦linux 下可以使用 vim jar 包,找到配置文件修改后再保存window 下需要使用 解压缩软件打开 jar 再找到配置文件,修改后替换更新 第二种方式的缺点是需要依赖外部容器,这无非多引入了一部分,很多时候我们很不情愿这么做 spring boot 项目启动时 指定配置有 2 种方式:一种是启动时修改配置参数,像 java -jar xxxx.jar –server.port=8081 这样;另外一种是 指定外部配置文件加载,像 java -jar xxxx.jar -Dspring.config.location=applixxx.yml 这样 目标我们希望打包成 to ...
无依赖其他任何 jar123456789101112131415161718<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</c ...
在 IDEA 中操作 Git GitLab 中有一个 git-branch-test 的项目 处于 master 分支 本地项目目录: 所在分支: 一般的工作流程: master 作为主分支, 一般都是用来发布最终版本的分支 当实现一个新需求时, 需要创建一个分支, 在新创建的分支上进行开发 这是已经实现的功能, 并且已经发布到 gitlab 服务器上的分支 (master): 12345678910111213141516171819202122public class HelloWorld { public static void main(String[] args) { String s = JOptionPane.showInputDialog("请输入一个整数"); int a = Integer.parseInt(s); System.out.println(a); if (isOdd(a)) System.out.println(&qu ...