IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:Java

共 216 篇相关文章

IT 累计浏览 44

解决访问 https 网站时,后端重定向或获取 URL 变成 http 的问题

在常见的Nginx反向代理后端Java应用的部署架构中,客户端与Nginx之间为HTTPS,但Nginx转发至后端服务器的请求协议为HTTP。这会导致后端应用通过`HttpServletRequest.getRequestURL()`获取到的URL为内网HTTP地址,且`HttpServletResponse.sendRedirect()`生成的重定向地址也为HTTP,无法反映真实的客户端访问协议。 解决此问题需结合Nginx配置与后端代码调整。对于URL获取问题,需在Nginx中通过`proxy_set_header Host $host`和`proxy_set_header X-Forwarded-Proto $scheme`向后端传递原始主机名与协议信息。后端Java应用则需通过自定义Servlet过滤器,读取`X-Forwarded-Proto`头并重写请求的`getScheme()`与`getRequestURL()`方法,确保返回正确的HTTPS URL。对于重定向问题,可通过Nginx的`proxy_redirect http:// $scheme://`指令,将后端响应中的Location头协议自动修正。 当架构中Nginx前存在负载均衡器时,需由负载均衡器透传`X-Forwarded-Proto`头,同时将Nginx配置中相关的`$scheme`变量替换为`$http_x_forwarded_proto`,以正确识别和传递最前端的访问协议。

IT 累计浏览 37

Java|FreeMarker 复用 layout

在 FreeMarker 项目中,页面布局的重复代码会随着页面增多而扩散,导致维护困难。常规的 include 指令可以提取公共头部和底部等元素,但每个页面仍需手动组合完整结构,一旦布局变更,修改成本较高。为消除这种重复,可以通过抽象布局模板来优化:利用 FreeMarker 的 macro 功能,定义一个统一的页面布局文件,其中包含固定组件并接收页面内容和脚本作为参数。具体页面只需导入该模板,并通过变量分配填充内容,从而实现布局与内容的分离。进一步,借助编辑器的代码片段功能,如 VSCode 的 code

IT 累计浏览 41

ClassPathXmlApplicationContext的不出网利用

ClassPathXmlApplicationContext是Spring框架中用于加载XML配置文件的核心类,其默认行为会从类路径加载资源。本文深入探讨了在无外部网络连接的环境下,如何利用该类的特性实现漏洞利用,聚焦于反序列化攻击向量。文章以Springboot Code-Breaking挑战为例,分析了在受限网络条件下,通过精心构造的XML配置文件触发反序列化过程,从而执行任意代码的技术细节。关键点包括:利用Spring的资源加载机制绕过网络限制,结合SnakeYAML等库的反序列化漏洞,实现在不出网的情况下完成攻击链。这不仅揭示了Spring应用在安全配置上的潜在风险,还提供了针对此类场景的防御建议,强调了代码审计中对于类路径处理和序列化安全的重视。

IT 累计浏览 55

当Nashorn失去括号:非典型Java命令执行绕过

针对Java Nashorn脚本环境中禁止使用小括号与中括号时执行任意命令的挑战,本文探讨了一种非常规的绕过思路。文章指出,Nashorn本质上是JavaScript引擎,而浏览器JavaScript中已存在无括号的XSS Payload技术,其核心在于避免直接调用函数时所需的括号。在此基础上,文章深入分析了如何将这一技术思路迁移到Nashorn的受限环境中,通过巧妙构造字符串并利用JavaScript隐式的函数调用机制(如通过运算符或属性访问触发),在无需显式编写括号的情况下,最终实现对如`java.lang.Runtime`等类方法的调用,从而达到执行系统命令的目的。该探讨为特定限制条件下的代码审计与安全防御提供了有价值的思路。

IT 累计浏览 2,140

2020 年个人总结

这篇讲的是猿辅导一位技术管理者对2020年的坦诚回顾。作者从公司年内完成35亿美元融资、估值升至155亿美元的行业背景切入,分享了自己入职8周年的感触,以及如何在新业务孵化中,从熟悉的线上产品研发跨入陌生的硬件与线下内容领域。 文章的核心在于“变化中的成长”。作者详述了从建立硬件团队、学习供应商管理,到团队协作开发绘本等具体挑战,揭示了从舒适区步入“不舒适状态”后的学习曲线。同时,通过列出自己评分的15本年度读物(包括3本9分推荐),并分享股票交易“不做空”等心得,展现了在工作高压下仍坚持多维学习与复盘的个人习惯。 作者也坦诚面对了年初目标未完全达成的遗憾,比如读书数量与游泳频率。最后,他提出了更聚焦的2021年目标:每年读12本书、坚持游泳,并更加关注自身心理状态。整篇文章融合了职场成长、商业洞察与个人生活思考,勾勒出一位技术人在业务快速扩张期如何寻找平衡、沉淀价值的完整画像。

IT 累计浏览 2,775

阿里巴巴的发展史 - 读《阿里铁军》

这篇讲的是作者读完《阿里铁军》后,对阿里巴巴早期发展史的梳理与思考。 文章首先勾勒了阿里的关键发展历程:从1999年创立、获得孙正义投资,到遭遇互联网泡沫时账上仅剩700万美元的生死危机。正是在绝境中诞生的“中国供应商”地推业务,凭借对出口经济窗口期的把握和一丝不苟的“陌拜”与复盘文化,意外成为了阿里的造血命脉。随后,马云在2003年力排众议布局淘宝与支付宝,以及2005年接管雅虎中国以获取关键技术人才,都被视为决定公司走向的战略节点。 作者将2001年的绝地求生和2003年的电商与支付双线布局,称为阿里的两个“创世时刻”。其核心观点在于,阿里的成功不仅是运气,更是将地推执行力、快速迭代的工作方式与坚韧的价值观(如“客户第一”)相结合的结果。文章通过分析孙正义投资、港股上市融得17亿美元为淘宝输血等具体事件,展现了资本、战略与业务执行之间的深刻互动。 对读者而言,这篇文章不仅是一部企业史,更揭示了在技术浪潮中,如何识别关键转折点、构建组织韧性,以及在“向管理要绩效”与“以业务代管理”之间寻找平衡的现实挑战。

IT 累计浏览 2,170

终端反编译字节码利器 CFR

这篇讲的是作者如何在终端下实现Java字节码的反编译。作者从个人对终端工作流的依赖出发,厌倦了JD-GUI这类图形化工具,转而寻找命令行解决方案,最终发现了CFR(Class File Reader)这款jar包工具。文章的核心在于展示CFR的实用命令:它可以单行反编译单个class文件,也能通过指定输出目录批量处理整个jar包。作者还贴心地将常用命令封装成了bash脚本,进一步简化操作。这种从需求出发、直接给出可运行命令的分享,让工具的上手路径非常清晰。对于习惯终端操作或需要快速、脚本化反编译场景的开发者来说,这是一个值得收录到工具箱的方案。

IT 累计浏览 2,261

一位资深Java的阿里系公司实战面试经验,套路还是面试官的多

这是一篇阿里系Java工程师的实战面试复盘。作者以亲历者视角,详细还原了从项目经验到技术基础的多轮面试场景,生动展现了面试官如何通过层层追问,考察候选人的知识深度和临场应变能力。 文章的核心亮点在于“场景还原”与“答题策略”。在项目经验环节,作者以Netty线程模型为例,演示了如何将问题引导至自己熟悉的领域,并分享了如何描述项目难点(如业务逻辑阻塞Work线程导致QPS上不去)及解决方案。在基础知识考察部分,以线程池原理和锁机制(Synchronized/ReentrantLock/CAS)为例,揭示了面试官常见的问题链——例如从线程池核心参数一路追问到“秒杀”场景下的线程池配置,或是从CAS原理深挖到其操作系统指令实现及ABA问题。 文章并非单纯罗列知识点,而是通过真实的对话片段,点明了一个关键:面试的“套路”实则是考察思维逻辑与知识内化程度。作者提醒,即便面对不记得的细节或不了解的领域(如读写锁),诚实沟通比硬撑更重要。对于正在准备技术面试的读者而言,这篇复盘的价值在于揭示了面试背后的考察逻辑,并提供了如何梳理项目故事、应对深度追问的实用思路。

IT 累计浏览 2,133

阿里面试题:为什么Map桶中个数超过8才转为红黑树

这篇讲的是一个经典的Java面试题:为什么HashMap的桶中链表长度达到8才转为红黑树?作者从一个好友的阿里面试经历切入,直接打开了源码中的注释,发现它只记录了阈值,却未解释原因。 文章的核心在于对源码“Implementation notes”的深入解读。作者指出,红黑树节点占用的空间是普通节点的两倍,因此转换是一种空间与时间的权衡。更关键的是,文章引用了源码中一段关于泊松分布的注释:在随机哈希算法下,桶中节点数量遵循特定的概率分布,链表长度达到8的概率极低(仅约千万分之六)。这从统计学角度证明了阈值8的选取并非随意,而是经过严谨计算的。 此外,文章也驳斥了一种常见但不够严谨的“性能对比”解释,强调了设计背后的科学性。通过剖析源码与概率模型,这篇文章将一个常见面试考点还原成了其严谨的设计思想,适合所有想理解Java集合框架底层优化的开发者。

IT 累计浏览 2,092

一起来学 Spring 2.X

这是一份针对 Spring Boot 2.x 的全面学习指南,由作者唐亚峰在其个人博客上连载。系列文章从最基础的构建第一个 Spring Boot 工程讲起,为读者铺设了一条清晰的学习路径。 整个系列系统性地覆盖了 Spring Boot 2.x 开发中的核心技术栈。作者不仅详细解释了配置管理、日志框架这些基础内容,还深入到整合 Thymeleaf 模板、使用 JdbcTemplate、Spring Data Jpa 以及 MyBatis 进行数据库访问的实战环节。对于进阶需求,文章进一步探讨了如何集成 Lettuce Redis 做缓存、利用 Spring Cache 二级缓存、接入 RabbitMQ 消息队列(包括延迟队列的实现),以及使用 Swagger 进行接口在线调试。 除了核心功能集成,系列也关注应用运维与工程化实践。例如,通过 Actuator 与 Spring Boot Admin 实现服务监控与管理,配置定时任务,实现文件上传与全局异常处理,以及借助 Liquibase 进行数据库版本管理。在安全与性能方面,讲解了整合 Shiro 安全框架,使用本地锁与分布式锁防止重复提交,并探讨了分布式限流方案的优雅实现。甚至包括 JDK8 日期格式化这种实用细节和 WebSocket 聊天室搭建这样的趣味课题。 这个系列最大的特点是循序渐进且内容扎实,每一讲都聚焦一个明确的主题并提供可运行的示例,非常适合希望从零开始或系统性巩固 Spring Boot 2.x 开发技能的读者作为案头参考。

IT 累计浏览 1,501

我的阿里面试之路

这篇讲的是作者长达三个月的阿里云技术岗面试全记录。与许多“面经”不同,它并非一份简单的答案清单,而是从面试者的视角出发,详细还原了从电话面到交叉面、最终拿到offer的曲折过程。 文章坦诚地分享了作者在算法题、系统设计以及技术深度探讨中遇到的具体挑战,尤其是几次因准备不足或理解偏差而差点“翻车”的真实时刻。作者从中总结出几个核心发现:阿里面试尤其看重对技术原理的深刻理解与现场推导能力,而非死记硬背;同时,清晰的沟通逻辑与展现解决问题的思维过程,有时比直接给出最优解更重要。 对于正在准备大厂技术面试,或是对阿里巴巴技术文化感兴趣的读者来说,这篇复盘不仅提供了实战细节,更揭示了面试背后对技术底蕴与临场应变能力的双重考验。它像一面镜子,能让读者在别人的经历中照见自己的准备方向。

IT 累计浏览 3,093

【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentLinkedQueue

这篇技术解析深入探讨了Java并发包中非阻塞线程安全队列ConcurrentLinkedQueue的实现原理。文章从线程安全队列的两种实现思路(阻塞与非阻塞)切入,重点剖析了ConcurrentLinkedQueue如何完全基于CAS算法(无锁)来实现其核心操作。 作者详细拆解了该队列必须遵循的四个关键不变性,并阐明了head与tail指针在更新时可以“滞后”的设计特性。全文的核心在于通过逐行解读offer()入列与poll()出列方法的源码,并辅以清晰的步骤图,生动展示了在多线程竞争环境下,新节点是如何被安全添加、以及头部节点如何被识别并移除的。分析中特别指出,像“p == q”这种看似异常的判断,正是处理并发删除与插入操作交错进行的关键所在,巧妙地解决了指针可能因并发更新而失效的难题。 通过这篇文章,读者能直观理解一种高性能并发容器如何在不使用锁的情况下,通过精巧的指针操作和CAS原子指令来保障线程安全与最终一致性。

IT 累计浏览 3,707

【死磕Java并发】—–Java内存模型之happend-before

这篇深入探讨了Java并发编程中一个关键却容易混淆的概念:happens-before原则。作者从多线程环境下变量修改的可见性问题出发,解释了JMM如何通过happens-before来建立内存可见性的保证。 文章系统梳理了happens-before的八大核心规则,例如程序次序规则(单线程内操作有序)、volatile变量规则(写操作对后续读操作可见)以及锁定规则(解锁先于加锁)。除了这些JVM原生规则,作者还列举了诸如线程安全集合操作、Future.get()等场景下的六条推导规则,构建了完整的判断体系。 为了帮助理解,文章通过简单的代码示例,一步步演示了如何应用这些规则来判断一段非同步代码是否存在线程安全风险。它明确了happens-before的本质:它并非强制操作顺序,而是保障了在存在该关系时,一个操作的结果对另一个操作的可见性。这为我们在并发编程中分析数据竞争、设计线程安全代码提供了根本依据。

IT 累计浏览 2,184

【死磕Java并发】—–Java内存模型之重排序

这篇文章深入探讨了Java内存模型中的重排序机制,解释了编译器和处理器为何以及如何在不破坏程序最终结果的前提下调整指令顺序。 作者从“as-if-serial”语义出发,结合具体代码示例(如`int a=1; int b=2; int c=a+b;`),清晰地阐述了在单线程环境下,只要不影响最终结果,操作间的顺序可以被优化重排。文章还特别指出了JVM对异常处理的特殊照顾,以确保`try-catch`块中的逻辑不被重排序破坏。 然而,文章的重点在于揭示重排序对多线程程序的潜在风险。通过一个使用了`volatile`的经典示例,作者展示了当两个线程共享变量且没有同步控制时,指令重排序(如赋值操作的顺序调换)可能导致其他线程观察到“中间状态”,从而破坏了程序预期的执行语义。这明确区分了重排序在单线程与多线程环境下的不同影响。 对于开发者而言,理解重排序是掌握Java并发编程中可见性问题的基础,它解释了为何在多线程场景下必须谨慎使用同步工具(如`volatile`或锁)来建立必要的内存屏障。

IT 累计浏览 2,980

【死磕Java并发】—–Java内存模型之分析volatile

这篇讲的是volatile关键字在Java内存模型(JMM)中的深层实现原理。作者从volatile的两大核心特性——可见性与禁止重排序出发,深入剖析了JMM是如何通过“内存屏障”这一底层机制来保证这些语义的。 文章通过一个经典的`VolatileTest`代码示例,生动演示了volatile读写操作如何与happens-before原则配合,确保跨线程的数据可见性。更硬核的部分在于对内存屏障插入策略的详解:JMM采取了保守策略,在volatile读/写前后精确插入StoreStore、StoreLoad、LoadLoad、LoadStore等屏障指令,以此强制维护操作的顺序性。 但巧妙之处不止于此。作者引用《Java并发编程的艺术》中的例子进一步说明,编译器在实际执行时会进行优化,只要不破坏volatile的内存语义,就可以省略部分冗余的屏障指令。这让我们看到,JMM的实现既保证了正确性,也蕴含着对性能的考量。对于想弄清楚volatile“凭什么”能起作用的开发者来说,这篇文章从理论到图解都梳理得相当清晰。

IT 累计浏览 2,184

【死磕Java并发】—–Java内存模型之从JMM角度分析DCL

这篇讲的是Java并发编程中一个经典而隐蔽的陷阱——双重检查锁定(DCL)在实现单例模式时,看似高效完美,实则潜藏因指令重排序导致的对象未初始化即被引用的严重问题。 作者从一个常见的错误懒汉式单例写法入手,逐步推导到试图优化性能的DCL写法。其核心矛盾在于:对象实例化包含“分配内存”、“初始化对象”和“引用赋值”三个步骤,而JVM或CPU可能对后两步进行重排序。这就意味着,在多线程环境下,其他线程可能看到一个已完成引用赋值、但尚未完成初始化的对象“半成品”,导致程序行为不可预期。 文章进而给出了两种标准解决方案。一种是利用`volatile`关键字的内存屏障语义,禁止实例初始化步骤的重排序,从而确保对象完全构造完毕后对其他线程才可见。另一种则是利用类加载机制,通过静态内部类延迟初始化,借助JVM对类初始化过程加锁的保证,来实现线程安全的单例。后者巧妙地将同步问题委托给了JVM本身,代码也更为简洁。 理解DCL的问题根源及解决方案,对于掌握Java内存模型中多线程可见性与指令重排序的实际影响至关重要。

IT 累计浏览 1,907

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输

这篇讲的是如何用Springboot快速搭建一个标准的Restful API服务。作者从一个完整的Web案例切入,演示了从数据库准备、项目结构解析到运行测试的全过程。核心聚焦在控制层的实现上,作者通过一个城市的增删改查Demo,清晰展示了如何使用`@RequestMapping`来映射不同的HTTP动词(GET/POST/PUT/DELETE),并配合`@PathVariable`和`@RequestBody`注解优雅地处理URL参数和请求体。文章还对REST风格的五大要素和HTTP方法做了简要知识梳理,帮助读者理解背后的设计理念。这是一个很典型的、即开即用的Springboot RESTful入门示例,体现了框架在简化Web服务开发上的便捷性。

IT 累计浏览 2,375

【死磕Java并发】—–深入分析synchronized的实现原理

这篇讲的是Java开发者最熟悉的synchronized关键字,但深入到了它鲜为人知的底层实现。文章从开发者早期对synchronized“重量级锁”的刻板印象出发,系统剖析了JDK 1.6对其进行的一系列优化,彻底改变了这一认知。 作者首先拆解了同步代码块与同步方法在JVM字节码层面的不同实现(monitorenter/monitorexit指令与ACC_SYNCHRONIZED标志),并指出这一切的基础在于Java对象头中的Mark Word和Monitor结构。其中,Mark Word被设计成可随锁状态动态复用的高效数据结构,是理解锁升级的关键。 文章的核心价值在于清晰梳理了JVM的锁优化机制:从通过“自旋等待”避免线程频繁挂起,到引入“适应性自旋”让虚拟机智能调整等待次数;从利用逃逸分析“消除”不必要的锁,到将连续操作“粗化”为更大范围的锁。最终,重点阐释了锁状态如何从无锁、偏向锁、轻量级锁一步步升级到重量级锁的完整路径,以及每一步升级的触发条件与设计意图。这不仅是理解synchronized的百科全书,也为开发者在实际编程中合理使用同步工具提供了底层视角。

IT 累计浏览 2,913

一次连接超时问题排查的历程

这是一次典型的、从迷茫到顿悟的故障排查历程。作者从一个Java应用启动时偶尔发生、且目标服务器不固定的数据库连接超时问题出发,展开了一场层层深入的调查。 排查始于网络抓包,但发现了更怪异的现象:部分TCP连接的SYN包似乎从未发出,而另一些则在收到服务器SYN/ACK后被客户端立即RST。通过strace工具,作者确认了所有connect系统调用均已执行,超时发生在内核的poll等待阶段,这解释了RST的由来,但问题的源头——从系统调用到网络发包之间那段莫名的“延迟”——依然成谜。 对内核网络栈的初步探索未果后,一次未过滤ARP包的抓包带来了转机。作者发现,连接失败的IP地址对应的ARP请求首次均无响应,需等待1秒后重试才成功。这1秒的延迟,足以让设定为50毫秒的连接超时大量失败。根因在于局域网存在广播限流,导致启动时ARP请求被丢弃,而一旦应用启动成功,持续的通信就会维持ARP缓存,故运行时再无此问题。 从复杂内核栈排查到基础的ARP缓存,作者也感慨这个原因“如此操蛋没技术含量”。但这个过程生动地说明,面对诡异的系统问题,保持开放的排查思路,并扎实地追踪数据流的每一环,是定位真相的关键。

IT 累计浏览 3,386

java enum枚举类型用法小结

这篇讲的是Java枚举(enum)的核心特性与实用技巧。文章从枚举的本质出发,指出它实际上是一种特殊的final类,继承自`java.lang.Enum`,所有枚举值都是`public static final`的常量。 作者通过示例代码,拆解了枚举的关键设计:其构造器必须私有,以确保外部无法实例化,这符合枚举作为常量集的初衷。接着,文章梳理了枚举类继承自Enum的常用方法,例如`ordinal()`用于获取声明顺序,`values()`能返回所有枚举值的数组,`valueOf()`则可根据字符串名称反向获取实例。 除了基础API,文章还着重展示了枚举的几种实战用法:用作类型安全的常量定义、在switch语句中提升代码可读性,以及如何向枚举中添加自定义字段和方法,使其承载更丰富的信息。这些内容覆盖了从入门到进阶的常见场景,能帮助开发者理解枚举不仅仅是一组常量,更是一个功能完备、封装良好的类型。