Spring
1. 现在要自己定义一个 AOP 来实现接口限流,怎么做
AOP 只是切入点,真正的限流核心一般放在 Redis + Lua,不会只靠本地内存。 先定义一个限流注解,打在需要限流的接口上,比如设置每秒最多多少次请求。然后再写一个切面,在请求进来时先拦截这个接口,拿到用户 ID、IP 或接口路径,拼成一个限流 key。接着去 Redis 里做计数和过期时间控制,如果超过阈值就直接拦住,返回“请求过于频繁”。 AOP 负责拦截,Redis 负责计数,真正上线一般不会只用本地内存,因为服务一旦是集群部署,本地限流就不准了。
扩展:
AOP:是面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,以减少系统的重复代码,降低模块间的耦合度。
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
你可以把AOP理解成:我不想在每个业务方法里都手动写一遍“日志、权限校验、事务、限流、异常处理”这些通用代码,所以我把这些公共逻辑单独拎出来,在方法执行前后“顺手插进去”。 比如下单、支付、查询订单,本来都是不同业务,但它们可能都要打日志、做权限判断,这些就属于“横切逻辑”。AOP 就是专门处理这种东西的。
Spring AOP 是怎么“偷偷加”的。 它不是直接改你原来的对象,而是给你套一个“代理对象”。
你调用的看起来是原来的方法,实际上先走代理:
- 先执行公共逻辑
- 再调用真实业务方法
- 最后再执行收尾逻辑
就像你去办事,不是直接见领导,而是先到秘书那里:
- 秘书先帮你登记
- 再带你去找领导
- 办完再帮你做记录
SpringAOP 怎么实现的
Spring AOP 是靠动态代理实现的,核心是在运行时生成代理对象,不用改源码就能给方法加功能。它有两种代理方式:如果被代理的类实现了接口,就用 JDK 自带的动态代理;如果没实现接口,就用第三方库,通过生成子类的方式做代理,两种方式配合,就能给任意类做切面增强
Spring AOP 的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。
Spring AOP 支持两种动态代理:
- 基于 JDK 的动态代理:使用
java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。 - 基于 CGLIB 的动态代理:当被代理的类没有实现接口时,Spring 会使用 CGLIB 库生成一个被代理类的子类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。
JDK 动态代理和 cglib 有啥区别
JDK 动态代理和 CGLIB 的核心区别主要在三点:
第一,JDK 只能代理实现了接口的类,靠委托机制实现;CGLIB 是给类生成子类,靠继承实现,能代理没接口的类,但不能代理 final 类。
第二,JDK 用反射调用,创建代理快但执行慢;CGLIB 改字节码生成子类,创建慢但执行快。
第三,JDK 是代理类和目标类实现同一接口,CGLIB 是代理类继承目标类,代理类可以直接赋值给目标类。
2. 怎么实现全局异常处理
用统一异常处理去做。 思路上分三层:第一层是业务异常,比如库存不足、余额不足,这种直接返回明确提示;第二层是参数异常,比如前端传参不合法;第三层是系统异常,统一兜底,避免把报错堆栈直接返回给前端。 另外返回结果要统一,比如状态码、提示信息、数据体这些字段保持一致。日志里再把请求参数、接口路径、异常信息记录下来,方便排查。
3. Java 哪些注解可以实现依赖注入
常见的三个:@Autowired、@Resource、@Inject。 另外像 @Value 也经常提到,但它更偏向注入配置值,不完全等同于注入一个 Bean。还有 @Service、@Component 这些是把类交给 Spring 管理,不是直接做注入,但它们也是整套依赖注入机制里的一部分。
Springboot
1. Spring Boot 自动装配
自动装配的意思就是,Spring Boot 会根据你引入的依赖、配置文件和当前环境,自动帮你把很多 Bean 配好,不用你一个个手动写配置。 比如你引入了数据库相关依赖,它就会尝试帮你把数据源、事务这些常用组件配起来。
底层大致可以理解成三步:
- 启动时加载自动配置类
- 判断当前条件是不是满足,比如类在不在、配置有没有写
- 满足条件就创建对应的 Bean
核心就是: 约定大于配置,省掉大量样板配置。