Advice优化

master
linlei 2024-04-28 14:08:40 +08:00
parent 706dddd31a
commit ec50207522
19 changed files with 94 additions and 90 deletions

View File

@ -15,7 +15,7 @@
### 二、基本描述 ### 二、基本描述
`AfterReturningAdvice`接口是Spring AOP框架中的一个核心接口用于在目标方法执行后拦截并执行自定义逻辑。通过实现该接口的`afterReturning`方法,可以在目标方法成功返回结果后进行一些操作,如日志记录、性能监控等 `AfterReturningAdvice`接口是Spring AOP框架中的一个核心接口用于在目标方法执行后拦截并执行自定义逻辑。通过实现该接口的`afterReturning`方法,可以在目标方法成功返回结果后进行一些操作。
### 三、主要功能 ### 三、主要功能
@ -24,7 +24,6 @@
+ 记录目标方法的执行情况,如方法名称、参数值、返回结果等,以便跟踪应用程序的运行状态。 + 记录目标方法的执行情况,如方法名称、参数值、返回结果等,以便跟踪应用程序的运行状态。
2. **性能监控** 2. **性能监控**
+ 统计目标方法的执行时间,分析应用程序的性能瓶颈,优化程序性能。 + 统计目标方法的执行时间,分析应用程序的性能瓶颈,优化程序性能。
3. **缓存处理** 3. **缓存处理**
@ -83,7 +82,7 @@ public class AfterReturningAdviceDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }
``` ```
@ -94,28 +93,27 @@ public class AfterReturningAdviceDemo {
public class MyAfterReturningAdvice implements AfterReturningAdvice { public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override @Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("After method " + method.getName() + " is called, returned value: " + returnValue); System.out.println("After Method " + method.getName());
} }
} }
``` ```
`MyService` 类是一个简单的服务类,其中包含了一个名为 `doSomething()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。 `MyService` 类是一个简单的服务类,其中包含了一个名为 `foo()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。
```java ```java
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world";
} }
} }
``` ```
运行结果,成功地执行了代理对象的`doSomething()`方法,并在方法执行完成后,后置返回通知`MyAfterReturningAdvice`被触发。 运行结果,成功地执行了代理对象的`foo()`方法,并在方法执行完成后,后置返回通知`MyAfterReturningAdvice`被触发。
```java ```java
Doing something... foo...
After method doSomething is called, returned value: hello world After Method foo
``` ```
### 七、常见问题 ### 七、常见问题

View File

@ -12,6 +12,6 @@ public class AfterReturningAdviceDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }

View File

@ -7,6 +7,6 @@ import java.lang.reflect.Method;
public class MyAfterReturningAdvice implements AfterReturningAdvice { public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override @Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("After method " + method.getName() + " is called, returned value: " + returnValue); System.out.println("After Method " + method.getName());
} }
} }

View File

@ -2,8 +2,7 @@ package com.xcs.spring;
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world";
} }
} }

View File

@ -1,14 +1,13 @@
## IntroductionInterceptor ## IntroductionInterceptor
- [IntroductionInterceptor](#IntroductionInterceptor) - [IntroductionInterceptor](#introductioninterceptor)
- [一、基本信息](#一基本信息) - [一、基本信息](#一基本信息)
- [二、基本描述](#二基本描述) - [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能) - [三、主要功能](#三主要功能)
- [四、接口源码](#四接口源码) - [四、接口源码](#四接口源码)
- [五、主要实现](#五主要实现) - [五、主要实现](#五主要实现)
- [六、最佳实践](#六最佳实践) - [六、最佳实践](#六最佳实践)
- [七、源码分析](#七源码分析) - [七、常见问题](#七常见问题)
- [八、常见问题](#八常见问题)
### 一、基本信息 ### 一、基本信息
@ -69,11 +68,11 @@ public class IntroductionInterceptorDemo {
// 创建代理对象 // 创建代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
// 开始监控 // 开始监控
((MyMonitoringCapable) proxy).toggleMonitoring(); ((MyMonitoringCapable) proxy).toggleMonitoring();
// 再次调用代理对象的方法 // 再次调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }
``` ```
@ -98,12 +97,11 @@ public class MyMonitoringIntroductionAdvice extends DelegatingIntroductionInterc
@Override @Override
protected Object doProceed(MethodInvocation mi) throws Throwable { protected Object doProceed(MethodInvocation mi) throws Throwable {
if (this.active) { if (this.active) {
System.out.println("开启监控..."); System.out.println("[开启监控" + mi.getMethod().getName() + "]");
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Object result = super.doProceed(mi); Object result = super.doProceed(mi);
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
System.out.println(mi.getClass().getName() + "." + mi.getMethod().getName() + " 耗费时间:" + (endTime - startTime) + " 毫秒"); System.out.println("[结束监控" + mi.getMethod().getName() + "] 耗费时间:" + (endTime - startTime) + " 毫秒");
System.out.println("结束监控...");
return result; return result;
} }
return super.doProceed(mi); return super.doProceed(mi);
@ -119,22 +117,34 @@ public interface MyMonitoringCapable {
} }
``` ```
`MyService` 类是一个简单的服务类,其中包含了一个名为 `doSomething()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。 `MyService` 类是一个简单的服务类,其中包含了一个名为 `foo()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。
```java ```java
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world"; try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} }
} }
}
```
运行结果,这个运行结果说明了引介通知成功地增强了目标方法,实现了在目标方法执行前后动态地添加额外的逻辑。
```java
foo...
[开启监控foo]
foo...
[结束监控foo] 耗费时间1008 毫秒
``` ```
### 七、常见问题 ### 七、常见问题
1. **引介的作用和优势是什么?** 1. **引介的作用和优势是什么?**
- 这个问题探讨了引介在 AOP 中的作用和优势,以及它与其他 AOP 概念(如通知、切点)的区别。 - 这个问题探讨了引介在 AOP 中的作用和优势,以及它与其他 AOP 概念(如通知、切点)的区别。
2. **如何实现引介?** 2. **如何实现引介?**

View File

@ -15,10 +15,10 @@ public class IntroductionInterceptorDemo {
// 创建代理对象 // 创建代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
// 开始监控 // 开始监控
((MyMonitoringCapable) proxy).toggleMonitoring(); ((MyMonitoringCapable) proxy).toggleMonitoring();
// 再次调用代理对象的方法 // 再次调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }

View File

@ -20,12 +20,11 @@ public class MyMonitoringIntroductionAdvice extends DelegatingIntroductionInterc
@Override @Override
protected Object doProceed(MethodInvocation mi) throws Throwable { protected Object doProceed(MethodInvocation mi) throws Throwable {
if (this.active) { if (this.active) {
System.out.println("开启监控..."); System.out.println("[开启监控" + mi.getMethod().getName() + "]");
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Object result = super.doProceed(mi); Object result = super.doProceed(mi);
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
System.out.println(mi.getClass().getName() + "." + mi.getMethod().getName() + " 耗费时间:" + (endTime - startTime) + " 毫秒"); System.out.println("[结束监控" + mi.getMethod().getName() + "] 耗费时间:" + (endTime - startTime) + " 毫秒");
System.out.println("结束监控...");
return result; return result;
} }
return super.doProceed(mi); return super.doProceed(mi);

View File

@ -2,8 +2,12 @@ package com.xcs.spring;
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world"; try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} }
} }

View File

@ -93,7 +93,7 @@ public class MethodBeforeAdviceDemo {
public class MyMethodBeforeAdvice implements MethodBeforeAdvice { public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override @Override
public void before(Method method, Object[] args, Object target) throws Throwable { public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method " + method.getName() + " is called."); System.out.println("Before method " + method.getName());
} }
} }
``` ```
@ -103,18 +103,17 @@ public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
```java ```java
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world";
} }
} }
``` ```
运行结果,调用目标方法`doSomething`之前,`MyMethodBeforeAdvice`中的前置通知被成功触发,并打印了相应的信息。 运行结果,调用目标方法`foo`之前,`MyMethodBeforeAdvice`中的前置通知被成功触发,并打印了相应的信息。
```java ```java
Before method doSomething is called. Before method foo
Doing something... foo...
``` ```
### 七、常见问题 ### 七、常见问题

View File

@ -12,6 +12,6 @@ public class MethodBeforeAdviceDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }

View File

@ -7,6 +7,6 @@ import java.lang.reflect.Method;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice { public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override @Override
public void before(Method method, Object[] args, Object target) throws Throwable { public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method " + method.getName() + " is called."); System.out.println("Before method " + method.getName());
} }
} }

View File

@ -2,8 +2,7 @@ package com.xcs.spring;
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world";
} }
} }

View File

@ -8,8 +8,6 @@
- [六、最佳实践](#六最佳实践) - [六、最佳实践](#六最佳实践)
- [七、常见问题](#七常见问题) - [七、常见问题](#七常见问题)
### 一、基本信息 ### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) ✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading)
@ -85,45 +83,45 @@ public class MethodInterceptorDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }
``` ```
`MyMethodInterceptor` 类用于实现方法拦截和增强的功能。在 `invoke()` 方法中,首先通过 `MethodInvocation` 对象获取被调用方法的信息,例如方法名等,并在方法调用之前输出方法被调用的信息。然后调用 `invocation.proceed()` 方法来执行原始方法,获取方法执行结果。最后,在方法调用之后输出方法返回值,并将其返回。 `MyMethodInterceptor` 类用于实现方法拦截和增强的功能。在 `invoke()` 方法中,首先通过 `MethodInvocation` 对象获取被调用方法的信息,例如方法名等,并在方法调用之前输出方法被调用的信息。然后调用 `invocation.proceed()` 方法来执行原始方法,获取方法执行结果。最后并将其返回。
```java ```java
public class MyMethodInterceptor implements MethodInterceptor { public class MyMethodInterceptor implements MethodInterceptor {
@Override @Override
public Object invoke(MethodInvocation invocation) throws Throwable { public Object invoke(MethodInvocation invocation) throws Throwable {
// 在方法调用之前执行的逻辑 // 在方法调用之前执行的逻辑
System.out.println("Method " + invocation.getMethod().getName() + " is called."); System.out.println("Before Method " + invocation.getMethod().getName());
// 调用原始方法 // 调用原始方法
Object result = invocation.proceed(); Object result = invocation.proceed();
// 在方法调用之后执行的逻辑 // 在方法调用之后执行的逻辑
System.out.println("Method " + invocation.getMethod().getName() + " returns " + result); System.out.println("After Method " + invocation.getMethod().getName());
return result; return result;
} }
} }
``` ```
`MyService` 类是一个简单的服务类,其中包含了一个名为 `doSomething()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。 `MyService` 类是一个简单的服务类,其中包含了一个名为 `foo()` 的方法。在上下文中,`MyService` 类被用作目标对象,即需要被拦截和增强的对象。
```java ```java
public class MyService { public class MyService {
public void doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
} }
} }
``` ```
运行结果,在调用 `MyService` 实例的 `doSomething()` 方法时,`MyMethodInterceptor` 拦截器成功地拦截了方法的执行,并在方法执行前后添加了额外的逻辑处理。 运行结果,在调用 `MyService` 实例的 `foo()` 方法时,`MyMethodInterceptor` 拦截器成功地拦截了方法的执行,并在方法执行前后添加了额外的逻辑处理。
```java ```java
Method doSomething is called. Before Method foo
Doing something... foo...
Method doSomething returns hello world After Method foo
``` ```
### 七、常见问题 ### 七、常见问题

View File

@ -1,8 +1,6 @@
package com.xcs.spring; package com.xcs.spring;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class MethodInterceptorDemo { public class MethodInterceptorDemo {
@ -10,10 +8,10 @@ public class MethodInterceptorDemo {
// 创建代理工厂&创建目标对象 // 创建代理工厂&创建目标对象
ProxyFactory proxyFactory = new ProxyFactory(new MyService()); ProxyFactory proxyFactory = new ProxyFactory(new MyService());
// 创建通知 // 创建通知
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(Pointcut.TRUE, new MyMethodInterceptor())); proxyFactory.addAdvice(new MyMethodInterceptor());
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomething(); proxy.foo();
} }
} }

View File

@ -7,11 +7,11 @@ public class MyMethodInterceptor implements MethodInterceptor {
@Override @Override
public Object invoke(MethodInvocation invocation) throws Throwable { public Object invoke(MethodInvocation invocation) throws Throwable {
// 在方法调用之前执行的逻辑 // 在方法调用之前执行的逻辑
System.out.println("Method " + invocation.getMethod().getName() + " is called."); System.out.println("Before Method " + invocation.getMethod().getName());
// 调用原始方法 // 调用原始方法
Object result = invocation.proceed(); Object result = invocation.proceed();
// 在方法调用之后执行的逻辑 // 在方法调用之后执行的逻辑
System.out.println("Method " + invocation.getMethod().getName() + " returns " + result); System.out.println("After Method " + invocation.getMethod().getName());
return result; return result;
} }
} }

View File

@ -2,8 +2,7 @@ package com.xcs.spring;
public class MyService { public class MyService {
public String doSomething() { public void foo() {
System.out.println("Doing something..."); System.out.println("foo...");
return "hello world";
} }
} }

View File

@ -16,7 +16,7 @@
### 二、基本描述 ### 二、基本描述
`ThrowsAdvice`接口是Spring AOP中的一种通知类型用于在方法抛出异常时执行额外的逻辑。实现该接口的类可以捕获方法抛出的异常并执行自定义的异常处理逻辑,比如记录日志、发送通知等 `ThrowsAdvice`接口是Spring AOP中的一种通知类型用于在方法抛出异常时执行额外的逻辑。实现该接口的类可以捕获方法抛出的异常并执行自定义的异常处理逻辑。
### 三、主要功能 ### 三、主要功能
@ -74,11 +74,12 @@ public interface ThrowsAdvice extends AfterAdvice {
### 五、主要实现 ### 五、主要实现
暂无 1. **ThrowsAdviceInterceptor**
+ 用于拦截方法抛出的异常,并触发相应的异常通知(`ThrowsAdvice`)。它负责捕获方法执行过程中抛出的异常,并调用相关的异常通知来处理异常情况。
### 六、最佳实践 ### 六、最佳实践
使用`ThrowsAdvice`接口来处理方法抛出的异常。它创建了一个代理工厂,并将目标对象(`MyService`)和异常通知(`MyThrowsAdvice`)传递给代理工厂。然后,它通过代理工厂获取代理对象,并调用代理对象的方法`doSomethingException()`。 使用`ThrowsAdvice`接口来处理方法抛出的异常。它创建了一个代理工厂,并将目标对象(`MyService`)和异常通知(`MyThrowsAdvice`)传递给代理工厂。然后,它通过代理工厂获取代理对象,并调用代理对象的方法`foo()`。
```java ```java
public class ThrowsAdviceDemo { public class ThrowsAdviceDemo {
@ -91,7 +92,7 @@ public class ThrowsAdviceDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomethingException(); proxy.foo();
} }
} }
``` ```
@ -106,19 +107,19 @@ public class MyThrowsAdvice implements ThrowsAdvice {
} }
``` ```
`MyService`类包含了一个名为`doSomethingException()`的方法,该方法执行某些操作,并故意引发了一个异常(通过除以零)。 `MyService`类包含了一个名为`foo()`的方法,该方法执行某些操作,并故意引发了一个异常(通过除以零)。
```java ```java
public class MyService { public class MyService {
public void doSomethingException() { public void foo() {
System.out.println("Doing something exception..."); System.out.println("foo...");
int i = 1 / 0; int i = 1 / 0;
} }
} }
``` ```
运行结果,当调用了`MyService`类的`doSomethingException()`方法,但在该方法中发生了除以零的错误,导致了`java.lang.ArithmeticException: / by zero`异常的抛出。 运行结果,当调用了`MyService`类的`foo()`方法,但在该方法中发生了除以零的错误,导致了`java.lang.ArithmeticException: / by zero`异常的抛出。
```java ```java
Doing something exception... Doing something exception...

View File

@ -2,8 +2,8 @@ package com.xcs.spring;
public class MyService { public class MyService {
public void doSomethingException() { public void foo() {
System.out.println("Doing something exception..."); System.out.println("foo...");
int i = 1 / 0; int i = 1 / 0;
} }
} }

View File

@ -12,6 +12,6 @@ public class ThrowsAdviceDemo {
// 获取代理对象 // 获取代理对象
MyService proxy = (MyService) proxyFactory.getProxy(); MyService proxy = (MyService) proxyFactory.getProxy();
// 调用代理对象的方法 // 调用代理对象的方法
proxy.doSomethingException(); proxy.foo();
} }
} }