IoC (Inversion of control )
控制反转:不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面去取即可。
- 降低对象间的耦合度,类的构造发生变化,不需要手动处理其他地方的创建,容器自动处理
- 资源管控更容易,避免资源重复定义出现浪费
- DI(Dependency Injection) 依赖注入,是最常见、最合理的实现方式
- spring 的 IoC 容器就是一个 Map
AOP(Aspect oriented programming)
什么是 AOP?
AOP(Aspect Oriented Programming)即面向切面编程,AOP 是 OOP(面向对象编程)的一种延续,二者互补,并不对立。
AOP 的目的是将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从核心业务逻辑中分离出来,通过动态代理、字节码操作等技术,实现代码的复用和解耦,提高代码的可维护性和可扩展性。OOP 的目的是将业务逻辑按照对象的属性和行为进行封装,通过类、对象、继承、多态等概念,实现代码的模块化和层次化(也能实现代码的复用),提高代码的可读性和可维护性。
AOP 为什么叫面向切面编程?
AOP 之所以叫面向切面编程,是因为它的核心思想就是将横切关注点从核心业务逻辑中分离出来,形成一个个的切面(Aspect)。
这里顺带总结一下 AOP 关键术语(不理解也没关系,可以继续往下看):
- 横切关注点(cross-cutting concerns) :多个类或对象中的公共行为(如日志记录)。
- 切面(Aspect):对横切关注点进行封装的类,一个切面是一个类(通常为注解类)。切面可以定义多个通知,用来实现具体的功能。
- 连接点(JoinPoint):方法调用的某个特定时刻(如方法调用、异常抛出等)。
- 通知(Advice):通知就是切面在某个连接点要执行的操作。通知有五种类型,分别是前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。前四种通知都是在目标方法的前后执行,而环绕通知可以控制目标方法的执行过程。
- 切点(Pointcut):一个切点是一个表达式,它用来匹配哪些连接点需要被切面所增强。(通常就是注解添加的地方)
- 织入(Weaving):织入是将切面和目标对象连接起来的过程,也就是将通知应用到切点匹配的连接点上。常见的织入时机有两种,分别是编译期织入(AspectJ)和运行期织入(AspectJ)。
AOP 解决了什么问题?
OOP 不能很好地处理一些分散在多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等),这些行为通常被称为 横切关注点(cross-cutting concerns) 。如果我们在每个类或对象中都重复实现这些行为,那么会导致代码的冗余、复杂和难以维护。
AOP 可以将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从 核心业务逻辑(core concerns,核心关注点) 中分离出来,实现关注点的分离。
通常AOP会配合注解一起使用。用注解定义切面
AOP 的应用场景有哪些?
- 日志记录:自定义日志记录注解,利用 AOP,一行代码即可实现日志记录。
- 性能统计:利用 AOP 在目标方法的执行前后统计方法的执行时间,方便优化和分析。
- 事务管理:
@Transactional注解可以让 Spring 为我们进行事务管理比如回滚异常操作,免去了重复的事务管理逻辑。@Transactional注解就是基于 AOP 实现的。 - 权限控制:利用 AOP 在目标方法执行前判断用户是否具备所需要的权限,如果具备,就执行目标方法,否则就不执行。例如,SpringSecurity 利用
@PreAuthorize注解一行代码即可自定义权限校验。 - 接口限流:利用 AOP 在目标方法执行前通过具体的限流算法和实现对请求进行限流处理。
- 缓存管理:利用 AOP 在目标方法执行前后进行缓存的读取和更新。
- ……
AOP 实现方式有哪些?
- JDK代理
- 需要被代理对象实现了某个类
- CGLib(Code Generation Library):
- 生成被代理对象的子类
- SpringAOP优先使用JDK Proxy,否则使用Cglib
- AspectJ:提供更强大的能力,可以完成编译时增强(也可以运行时增强),性能更好,SpringAOP是运行时增强
