为什么用线程池 创建 / 销毁线程伴随着系统开销, 过于频繁的创建 / 销毁线程, 会很大程度上影响处 - 理效率 线程并发数量过多, 抢占系统资源从而导致阻塞 对线程进行一些简单的管理 在 Java 中, 线程池的概念是 Executor 这个接口, 具体实现为 ThreadPoolExecutor 类, 学习 Java 中的线程池, 就可以直接学习他了对线程池的配置, 就是对ThreadPoolExecutor 构造函数的参数的配置 构造函数:1234567891011121314151617181920212223242526272829303132// 五个参数的构造函数public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, ...
之前一直学习 SpringCloud, 对于配置中心,一直也是采用的 Spring Cloud Config,但是用久了,发现很多地方满足不了要求,同时也感觉很 low(个人看法勿喷)。在学习 Spring cloud config 的时候也有听到过携程的 apollo,但一直没时间去弄。直到昨天看了一张图,如下:使我下定决心去看看携程的 apollo 配置中心。 这张图也算是综合对比了 spring cloud config,netflix archaius, ctrip apollo, disconf, hawk 等配置中心的功能点。综合比较下来携程 apollo 更具有优势。 二、简单介绍携程 Apollo 配置中心1、What is Apollo1.1 背景随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址…… 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制…… 在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。 Apollo 配置中 ...
现有架构日志存在的问题 关键逻辑无日志埋点 日志级别规范 生产环境日志级别不正确, 不规范 日志配置不统一 日志框架不统一 日志打语句不规范 因此针对以上问题, 对整个项目中的日志进行规范管理 统一日志配置新框架中统一使用 log4j2 日志框架来进行日志管理 具有的功能: 根据不同的环境输出不同的日志级别 开发环境, 输出等级为 debug 测试和生成环境, 输出等级为 info 开发环境, 只输出到 console 测试和生产环境, 输出到 /usr/logs/app_name/port/all.log, 关闭 console 输出 按天压缩日志 自动删除 30 天以前的日志 统一输出格式 动态修改日志等级 现有日志修改现在的代码暂时不能全部迁移到新框架, 考虑到现在各个模块使用的日志配置不统一, 日志配置不合理, 这里规范一下日志相关的配置 统一配置格式由于老项目中一部分使用 log4j, 另一部分又使用了 log4j2 日志框架,配置文件一部分是 xml, 另一部分又是 properties. 为了以后迁 ...
新时代码农
未读开发中日志这个问题,每个公司都强调,也制定了一大堆规范,但根据实际情况看,效果不是很明显,主要是这个东西不好测试和考核,没有日志功能一样跑啊。 但是没有日志, 一旦系统出现问题, 将导致排查问题时困难重重.因此好的日志输出有利于快速定位问题 但是我们在什么时候打印日志? 需要打印什么信息? 用什么日志级别?这些问题都将应用我们排查问题时的速度 因此这里制定一个日志规范, 将日志相关的常识性问题做一个总结. 日志等级说明 trace, debug: 理论上 “不属于错误”, 只是打印一些状态, 提示信息, 以便 开发过程 中观察. info: 理论上 “不属于错误”, 只是一些提示性的信息, 但是即使在开发完成, 正式上线的系统中, 也有保留的价值. warn: 属于轻微的 “警告”, 程序中出现了一些异常情况, 但是影响不大, 还可以正常使用. error: 属于 “普通的错误”, 在程序可以控制的范围内, 不会造成连锁影响或巨大影响. fatal: 属于 “致命错误”, 可导致整个系统或者一系列功能无法使用, 甚至导致系统瘫痪, 关闭. 规范 日志必须显示 日志等级, ...
多个模块有登录需求, 但是代码都是相互拷贝, 没有做统一处理 优化方案将登录逻辑封装成模块, 作为插件提供服务 shiro 认证过程1. 收集实体/凭据信息1UsernamePasswordToken token = new UsernamePasswordToken(username, password, true); UsernamePasswordToken 支持最常见的用户名/密码的认证机制。同时,由于它实现了 Rarraydsj@163.comemberMeAuthenticationToken 接口,我们可以通过令牌设置“记住我”的功能。但 ...
需要的环境: 具有公网 IP 的服务器, 运行 proxy-server 一台内网 pc 或服务器, 运行 proxy-client lanproxy nginx JDK 准备工作使用 阿里云 服务器, ip 为 111.111.111.111, 已经安装好了 nginx 和 JDK8 下载 proxy-server 和 proxy-client https://github.com/ffay/lanproxy/releases 修改 hosts 文件 12111.111.111.111 ivr.wechat.com111.111.111.111 local.ivr.wechat.com proxy-server 搭建 解压 proxy-server.zip 修改配置文件 conf/config.properties, 修改用户名和密码 启动服务 /usr/local/proxy-server/bin/startup.sh config.properties 1234567891011121314151617181920server.bind=0.0.0.0# 普通端口 ...
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 ...