@@ -87,221 +87,6 @@ AOP 的目的是将横切关注点(如日志记录、事务管理、权限控
8787
8888AOP 之所以叫面向切面编程,是因为它的核心思想就是将横切关注点从核心业务逻辑中分离出来,形成一个个的** 切面(Aspect)** 。
8989
90- 这里顺带总结一下 AOP 关键术语:
91-
92- - ** 横切关注点(cross-cutting concerns)** :多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等)。
93- - ** 切面(Aspect)** :对横切关注点进行封装的类,一个切面是一个类。切面可以定义多个通知,用来实现具体的功能。
94- - ** 连接点(JoinPoint)** :连接点是方法调用或者方法执行时的某个特定时刻(如方法调用、异常抛出等)。
95- - ** 通知(Advice)** :通知就是切面在某个连接点要执行的操作。通知有五种类型,分别是前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。前四种通知都是在目标方法的前后执行,而环绕通知可以控制目标方法的执行过程。
96- - ** 切点(Pointcut)** :一个切点是一个表达式,它用来匹配哪些连接点需要被切面所增强。切点可以通过注解、正则表达式、逻辑运算等方式来定义。比如 ` execution(* com.xyz.service..*(..)) ` 匹配 ` com.xyz.service ` 包及其子包下的类或接口。
97- - ** 织入(Weaving)** :织入是将切面和目标对象连接起来的过程,也就是将通知应用到切点匹配的连接点上。常见的织入时机有两种,分别是编译期织入(AspectJ)和运行期织入(AspectJ)。
98-
99- ### AOP 解决了什么问题?
100-
101- OOP 不能很好地处理一些分散在多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等),这些行为通常被称为 ** 横切关注点(cross-cutting concerns)** 。如果我们在每个类或对象中都重复实现这些行为,那么会导致代码的冗余、复杂和难以维护。
102-
103- AOP 可以将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从** 核心业务逻辑(core concerns,核心关注点)** 中分离出来,实现关注点的分离。
104-
105- ![ ] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/crosscut-logic-and-businesslogic-separation%20%20%20%20%20%20.png )
106-
107- 以日志记录为例进行介绍,假如我们需要对某些方法进行统一格式的日志记录,没有使用 AOP 技术之前,我们需要挨个写日志记录的逻辑代码,全是重复的的逻辑。
108-
109- ``` java
110- public CommonResponse<Object > method1() {
111- // 业务逻辑
112- xxService. method1();
113- // 省略具体的业务处理逻辑
114- // 日志记录
115- ServletRequestAttributes attributes = (ServletRequestAttributes ) RequestContextHolder . getRequestAttributes();
116- HttpServletRequest request = attributes. getRequest();
117- // 省略记录日志的具体逻辑 如:获取各种信息,写入数据库等操作...
118- return CommonResponse . success();
119- }
120-
121- public CommonResponse<Object > method2() {
122- // 业务逻辑
123- xxService. method2();
124- // 省略具体的业务处理逻辑
125- // 日志记录
126- ServletRequestAttributes attributes = (ServletRequestAttributes ) RequestContextHolder . getRequestAttributes();
127- HttpServletRequest request = attributes. getRequest();
128- // 省略记录日志的具体逻辑 如:获取各种信息,写入数据库等操作...
129- return CommonResponse . success();
130- }
131-
132- // ...
133- ```
134-
135- 使用 AOP 技术之后,我们可以日志记录的逻辑封装成一个切面,然后通过切入点和通知来指定在哪些方法需要执行日志记录的操作。
136-
137- ``` java
138-
139- // 日志注解
140- @Target ({ElementType . PARAMETER ,ElementType . METHOD })
141- @Retention (RetentionPolicy . RUNTIME )
142- @Documented
143- public @interface Log {
144-
145- /**
146- * 描述
147- */
148- String description () default "";
149-
150- /**
151- * 方法类型 INSERT DELETE UPDATE OTHER
152- */
153- MethodType methodType () default MethodType.OTHER;
154- }
155-
156- // 日志切面
157- @Component
158- @Aspect
159- public class LogAspect {
160- // 切入点,所有被 Log 注解标注的方法
161- @Pointcut (" @annotation(cn.javaguide.annotation.Log)" )
162- public void webLog () {
163- }
164-
165- /**
166- * 环绕通知
167- */
168- @Around (" webLog()" )
169- public Object doAround (ProceedingJoinPoint joinPoint ) throws Throwable {
170- // 省略具体的处理逻辑
171- }
172-
173- // 省略其他代码
174- }
175- ```
176-
177- 这样的话,我们一行注解即可实现日志记录:
178-
179- ``` java
180- @Log (description = " method1" ,methodType = MethodType . INSERT )
181- public CommonResponse<Object > method1() {
182- // 业务逻辑
183- xxService. method1();
184- // 省略具体的业务处理逻辑
185- return CommonResponse . success();
186- }
187- ```
188-
189- ### AOP 的应用场景有哪些?
190-
191- - 日志记录:自定义日志记录注解,利用 AOP,一行代码即可实现日志记录。
192- - 性能统计:利用 AOP 在目标方法的执行前后统计方法的执行时间,方便优化和分析。
193- - 事务管理:` @Transactional ` 注解可以让 Spring 为我们进行事务管理比如回滚异常操作,免去了重复的事务管理逻辑。` @Transactional ` 注解就是基于 AOP 实现的。
194- - 权限控制:利用 AOP 在目标方法执行前判断用户是否具备所需要的权限,如果具备,就执行目标方法,否则就不执行。例如,SpringSecurity 利用` @PreAuthorize ` 注解一行代码即可自定义权限校验。
195- - 接口限流:利用 AOP 在目标方法执行前通过具体的限流算法和实现对请求进行限流处理。
196- - 缓存管理:利用 AOP 在目标方法执行前后进行缓存的读取和更新。
197- - ......
198-
199- ### AOP 实现方式有哪些?
200-
201- AOP 的常见实现方式有动态代理、字节码操作等方式。
202-
203- Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 ** JDK Proxy** ,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 ** Cglib** 生成一个被代理对象的子类来作为代理,如下图所示:
204-
205- ![ SpringAOPProcess] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/230ae587a322d6e4d09510161987d346.jpeg )
206-
207- 当然你也可以使用 ** AspectJ** !Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
208-
209- ** Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。** Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
210-
211- Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
212-
213- ## 如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。
214-
215- title: IoC & AOP 详解(快速搞懂)
216- category: 框架
217- tag:
218-
219- - Spring
220-
221- ---
222-
223- 这篇文章会从下面从以下几个问题展开对 IoC & AOP 的解释
224-
225- - 什么是 IoC?
226- - IoC 解决了什么问题?
227- - IoC 和 DI 的区别?
228- - 什么是 AOP?
229- - AOP 解决了什么问题?
230- - AOP 的应用场景有哪些?
231- - AOP 为什么叫做切面编程?
232- - AOP 实现方式有哪些?
233-
234- 首先声明:IoC & AOP 不是 Spring 提出来的,它们在 Spring 之前其实已经存在了,只不过当时更加偏向于理论。Spring 在技术层次将这两个思想进行了很好的实现。
235-
236- ## IoC (Inversion of control )
237-
238- ### 什么是 IoC?
239-
240- IoC (Inversion of Control )即控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题。
241-
242- 例如:现有类 A 依赖于类 B
243-
244- - ** 传统的开发方式** :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
245- - ** 使用 IoC 思想的开发方式** :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面过去即可。
246-
247- 从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情)
248-
249- ** 为什么叫控制反转?**
250-
251- - ** 控制** :指的是对象创建(实例化、管理)的权力
252- - ** 反转** :控制权交给外部环境(IoC 容器)
253-
254- ![ IoC 图解] ( https://oss.javaguide.cn/java-guide-blog/frc-365faceb5697f04f31399937c059c162.png )
255-
256- ### IoC 解决了什么问题?
257-
258- IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?
259-
260- 1 . 对象之间的耦合度或者说依赖程度降低;
261- 2 . 资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。
262-
263- 例如:现有一个针对 User 的操作,利用 Service 和 Dao 两层结构进行开发
264-
265- 在没有使用 IoC 思想的情况下,Service 层想要使用 Dao 层的具体实现的话,需要通过 new 关键字在` UserServiceImpl ` 中手动 new 出 ` IUserDao ` 的具体实现类 ` UserDaoImpl ` (不能直接 new 接口类)。
266-
267- ![ ] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/ioc-kfji3.png )
268-
269- 很完美,这种方式也是可以实现的,但是我们想象一下如下场景:
270-
271- 开发过程中突然接到一个新的需求,针对对` IUserDao ` 接口开发出另一个具体实现类。因为 Server 层依赖了` IUserDao ` 的具体实现,所以我们需要修改` UserServiceImpl ` 中 new 的对象。如果只有一个类引用了` IUserDao ` 的具体实现,可能觉得还好,修改起来也不是很费力气,但是如果有许许多多的地方都引用了` IUserDao ` 的具体实现的话,一旦需要更换` IUserDao ` 的实现方式,那修改起来将会非常的头疼。
272-
273- ![ ] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/why-ioc.png )
274-
275- 使用 IoC 的思想,我们将对象的控制权(创建、管理)交有 IoC 容器去管理,我们在使用的时候直接向 IoC 容器 “要” 就可以了
276-
277- ![ ] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/why-ioc-2.png )
278-
279- ### IoC 和 DI 有区别吗?
280-
281- IoC(Inverse of Control:控制反转)是一种设计思想或者说是某种模式。这个设计思想就是 ** 将原本在程序中手动创建对象的控制权交给第三方比如 IoC 容易。** 对于我们常用的 Spring 框架来说, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。不过,IoC 在其他语言中也有应用,并非 Spring 特有。
282-
283- IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。
284-
285- 老马(Martin Fowler)在一篇文章中提到将 IoC 改名为 DI,原文如下,原文地址:< https://martinfowler.com/articles/injection.html > 。
286-
287- ![ ] ( https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/martin-fowler-injection.png )
288-
289- 老马的大概意思是 IoC 太普遍并且不表意,很多人会因此而迷惑,所以,使用 DI 来精确指名这个模式比较好。
290-
291- ## AOP(Aspect oriented programming)
292-
293- 这里不会涉及太多专业的术语,核心目的是将 AOP 的思想说清楚。
294-
295- ### 什么是 AOP?
296-
297- AOP(Aspect Oriented Programming)即面向切面编程,AOP 是 OOP(面向对象编程)的一种延续,二者互补,并不对立。
298-
299- AOP 的目的是将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从核心业务逻辑中分离出来,通过动态代理、字节码操作等技术,实现代码的复用和解耦,提高代码的可维护性和可扩展性。OOP 的目的是将业务逻辑按照对象的属性和行为进行封装,通过类、对象、继承、多态等概念,实现代码的模块化和层次化(也能实现代码的复用),提高代码的可读性和可维护性。
300-
301- ### AOP 为什么叫面向切面编程?
302-
303- AOP 之所以叫面向切面编程,是因为它的核心思想就是将横切关注点从核心业务逻辑中分离出来,形成一个个的** 切面(Aspect)** 。
304-
30590这里顺带总结一下 AOP 关键术语(不理解也没关系,可以继续往下看):
30691
30792- ** 横切关注点(cross-cutting concerns)** :多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等)。
0 commit comments