框架与微服务

浏览该分类下的所有文章

分布式(二)

本文围绕分布式系统的最终一致性展开,首先介绍了Open Group 的 DTS 模型及 JEE 中的 TX、XA 协议,并详细说明了两阶段提交、三阶段提交以及阿里提出的 TCC 方案的流程、优缺点。随后提出在高并发场景下实现最终一致性的实用模式:查询、补偿、异步确保、定期校对、可靠消息以及缓存一致性,并给出相应的实现要点。接着讨论了分布式单点故障,分别阐述了无状态服务的冗余方案和有状态服务的主备、选举(ZooKeeper、Paxos、Raft)机制。最后简要对比了 HTTP 与 RPC 在协议、性能、负载均衡和服务治理等方面的区别,指出 RPC 更适合内部高效调用。

SpringBoot绕过Nginx代理获取客户端真实IP的解决方案

本文介绍在 SpringBoot 项目中通过 Nginx 代理获取客户端真实 IP 并解析其归属地的实现方案。首先在 Nginx 配置 `X-Real-IP` 与 `X-Forwarded-For` 头部,将真实 IP 传递给后端;随后编写 `IpUtil` 工具类,从请求头或 `request.getRemoteAddr()` 读取 IP;引入 `ip2region` 库并在资源目录放置 `ip2region.db`,使用 B‑tree 算法查询 IP 对应的省、市或国家信息;最后在控制层调用 `IpUtil.getIpAddr` 与 `IpUtil.getIpPossession`,将解析结果显示在评论区,实现博客评论的 IP 属地展示。

微服务接口设计原则

微服务通过原子、独立、去中心化的方式实现业务拆分,接口设计需兼顾高可用、高性能和易维护。关键原则包括:降级兜底、过载保护与流量限流、快速失败与超时、无状态与最少依赖、简洁可靠、分散与隔离、幂等和故障自愈;在分布式环境下根据 CAP 定理在一致性和可用性之间权衡,采用 BASE 理论实现基本可用、软状态和最终一致性。性能上尽量使用无锁数据结构和单线程模型,避免锁竞争。遵循这些原则可构建可靠、弹性、可扩展的微服务接口。

解决SpringBoot打成jar包无法加载resources下文件的问题

文章介绍了SpringBoot 打成 jar 包后在 Linux 环境中无法直接读取 resources 目录下文件(如 application.yml、ip2region.db)的常见问题,并提供了解决方案。核心思路是使用 Spring 提供的 PathMatchingResourcePatternResolver 获取资源对象,再通过 Apache Commons IO 的 FileUtils.copyInputStreamToFile 将资源流写入本地文件,从而实现对 jar 包内部资源的读取。文中给出完整代码示例,并列出所需的核心依赖(spring‑core 与 commons‑io),帮助开发者在部署时顺利加载 resources 中的文件。

过多赠予,无所适从

本文以 Spring @Autowired 为例,解析“required a single bean, but 2 were found”错误的根源——在容器中存在同类型的多个 Bean,且缺乏 @Primary、@Priority 或名称匹配等优先级标识,导致 Spring 无法决定注入对象。通过源码剖析展示了 Bean 的实例化与属性填充过程以及 AutowiredAnnotationBeanPostProcessor 的工作原理。解决思路包括为其中一个实现加 @Primary、使用 @Qualifier 或通过属性名与 Bean 名称精确匹配等方式,以明确注入目标,进而消除冲突。

原型 Bean 被固定

Spring 中把 @Service 标记为原型(@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE))的 Bean 注入到单例 @RestController 的字段时,Autowired 只在容器创建控制器时一次性实例化并固定该对象,导致原型作用失效并出现启动错误。源码分析显示 AutowiredAnnotationBeanPostProcessor 在 populateBean 阶段通过反射把找到的 Bean 直接赋值给字段,后续不再重新获取。解决办法有两种:①注入 ApplicationContext 并在方法中调用 applicationContext.getBean(ServiceImpl.class) 每次获取新实例;②在控制器中声明带 @Lookup 的抽象方法 getServiceImpl(),Spring 利用 CGLIB 生成子类并在调用时从 BeanFactory 动态获取原型 Bean。两种方式均能保证每次请求得到新的 ServiceImpl。文章还解释了 @Lookup 的实现原理以及 Spring 通过反射和方法覆盖实现原型注入的细节,提醒使用者注意单例‑原型混用的潜在陷阱。

定义的 Bean 缺少隐式依赖

文章指出,Spring 在创建标记为 @Service(或其他注解)的 Bean 时,如果该类显式声明了构造器,容器会依据构造器参数类型自动在 BeanFactory 中查找对应的 Bean 并注入。若参数(如 String)没有相应的 Bean,Spring 在 AbstractAutowireCapableBeanFactory#createBeanInstance → autowireConstructor → resolveDependency 过程中抛出 “Parameter … could not be found” 异常。解决办法是为构造器参数提供相应的 Bean(如通过 @Bean 定义 String serviceName()),或避免出现多个可选构造器导致歧义。文章提醒开发者不要把 Spring Bean 当作普通对象直接 new,需了解其隐式依赖规则,以免出现装配失败。

隐式扫描不到 Bean 的定义

Spring Boot 启动类使用 @SpringBootApplication 时,内部的 @ComponentScan 若未指定 basePackages,会默认扫描启动类所在的包。将 Controller 移到其他包后超出默认扫描范围,导致 Bean 找不到,应用失效。解决办法是显式配置扫描路径,如在启动类上添加 @ComponentScan("com.zou.controller"),或使用 @ComponentScans 指定多个包。需要注意显式指定后默认包不再被扫描,避免遗漏。

聊聊幂等设计

幂等指一次或多次请求产生相同副作用,常用于防止超时重试导致的重复操作。为保证幂等,需要为每个请求生成全局唯一ID(如UUID、Snowflake),并在业务层通过唯一索引、主键冲突、状态机、独立防重表、token、悲观/乐观锁、分布式锁等八种方式实现过滤重复。接口超时可先查询结果或直接重试前提是下游提供幂等保障。文中还说明了 HTTP 方法的幂等性:GET、HEAD、OPTIONS、DELETE、PUT 为幂等,POST 不具幂等。

Dubbo最佳实战

Dubbo是高性能的 Java RPC 框架,官方推荐使用 Zookeeper 作为服务注册中心。文章先概述 Dubbo 的特性与服务治理,随后通过一个基于 Maven 的完整实战案例演示其使用流程:①创建 service‑api 模块定义公共接口;②在 provider 模块引入该接口并实现类,用 @Service 注解将服务注册到 Zookeeper;③在 consumer 模块同样引入接口,通过 @Reference 调用服务。文中提供了所有 Maven 依赖、properties 配置、启动代码以及运行步骤(启动本机 Zookeeper、启动提供者、启动消费者,回车键触发调用),完整源码已上传至 GitHub。

自定义持久层框架(仿MyBatis)

本文介绍了一个仿 MyBatis 的持久层框架实现思路。首先在使用端准备 sqlMapConfig.xml(存放数据源)和 Mapper.xml(定义 SQL 与唯一标识),并建立实体类。框架端通过 Resources 将配置文件读取为流,使用 dom4j 解析后封装到 Configuration(保存 DataSource 与 Map\<statementId, MappedStatement\>)和 MappedStatement(保存 id、resultType、parameterType、sql)中。SqlSessionFactoryBuilder 负责构建 Configuration 并生成 DefaultSqlSessionFactory,openSession() 返回 SqlSession 实例,提供 selectList、selectOne 等 CRUD 方法,内部基于 JDBC 完成数据库操作。整体采用 Builder、Factory、Proxy 等设计模式,并给出完整的 Maven 依赖、数据库建表脚本及代码示例,展示了从配置解析到会话执行的完整流程。

Spring AOP底层原理

Spring AOP 通过动态代理实现横向切面功能。若目标对象实现接口,Spring 使用 JDK Proxy 创建与接口同级的代理对象;若未实现接口,则采用 CGLIB 生成目标类的子类作为代理。代理对象在运行时拦截方法调用,实现与原实现类相同的功能,而无需修改源代码,从而完成 AOP 的横向扩展。