# ByxAOP
**Repository Path**: byx2000/ByxAOP
## Basic Information
- **Project Name**: ByxAOP
- **Description**: Simple AOP framework.(简易AOP框架)
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-02-23
- **Last Updated**: 2022-05-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: aop
## README
# ByxAOP——简易AOP框架
ByxAOP是一个简易AOP框架,基于JDK动态代理和CGLIB动态代理,支持前置增强、后置增强、环绕增强、异常增强四种增强类型。
## Maven引入
```xml
byx-maven-repo
byx-maven-repo
https://gitee.com/byx2000/maven-repo/raw/master/
byx.aop
byx-aop
1.0.0
```
## API文档
[API文档](http://byx2000.gitee.io/javadoc/ByxAOP-1.0.0-javadoc/)
## 使用示例
下面通过一个简单的例子来快速了解ByxAOP的使用。
`UserService`接口:
```java
public interface UserService {
boolean login(String username, String password);
}
```
`UserServiceImpl`实现类:
```java
public class UserServiceImpl implements UserService {
@Override
public boolean login(String username, String password) {
System.out.println("in login");
return true;
}
}
```
`UserServiceAdvice`增强类:
```java
public class UserServiceAdvice {
@Around
@Filter(name = "login")
public boolean aroundLogin(TargetMethod targetMethod) {
System.out.println("before login");
System.out.println("params: " + Arrays.toString(targetMethod.getParams()));
boolean ret = (boolean) targetMethod.invokeWithOriginalParams();
System.out.println("after login");
System.out.println("return value: " + ret);
return ret;
}
}
```
主函数:
```java
public static void main(String[] args) {
UserService userService = ByxAOP.getAopProxy(new UserServiceImpl(), new UserServiceAdvice());
userService.login("aaa", "123");
}
```
控制台输出结果:
```
before login
params: [aaa, 123]
in login
after login
return value: true
```
从输出结果可以看到,`UserServiceImpl`的`login`方法被增强了。
## 创建AOP代理类
使用`ByxAOP`中的静态方法`getAopProxy`来创建AOP代理类:
```java
public static T getAopProxy(T target, Object advice);
```
* `target`是目标对象,即被增强的对象
* `advice`是目标对象的增强类,其中包含了若干方法,每个方法都表示对目标对象中特定方法的增强和拦截,这些信息通过注解来配置
## 拦截类型注解
ByxAOP支持如下拦截类型注解:
|注解|说明|
|---|---|
|`@Before`|前置增强,可以拦截和修改方法参数|
|`@After`|后置增强,可以拦截和修改方法返回值|
|`@Around`|环绕增强,可以自定义拦截方式|
|`@Replace`|替换目标方法的实现|
|`@AfterThrowing`|拦截方法异常|
### @Before
该注解用于对目标方法进行前置增强。
目标方法:
```java
public int target(int a, String b) {
...
}
```
前置增强有三种使用方式:
1. 在目标方法调用之前执行自定义操作
```java
@Before
public void beforeTarget() {
// 自定义操作...
}
```
2. 获取目标方法的参数并执行自定义操作,但不修改参数值
```java
@Before
public void beforeTarget(int n) {
// n为传入目标方法的参数值
// 自定义操作...
}
```
3. 拦截目标方法的参数,并可修改目标方法的参数
```java
@Before
public Object[] beforeTarget(int a, String b) {
// 自定义操作...
// 返回修改后的方法参数数组
return new Object[]{...};
}
```
### @After
该注解用于对目标方法进行后置增强。
目标方法:
```java
public String target(String a, String b) {
...
}
```
后置增强有三种使用方式:
1. 在目标方法返回之后执行自定义操作
```java
@After
public void afterTarget() {
// 自定义操作...
}
```
2. 接收目标方法的返回值并执行自定义操作,但不修改返回值
```java
@After
public void afterTarget(int retVal) {
// retVal为目标方法的返回值
// 自定义操作...
}
```
3. 拦截目标方法的返回值,并可修改目标方法的返回值
```java
@After
public String afterTarget(String retVal) {
// 自定义操作...
// 返回一个新的返回值
return ...;
}
```
### @Around
该注解用于对目标方法进行环绕增强。用户可以通过环绕增强实现自定义的拦截操作,其它所有增强类型都能用环绕增强实现。被`@Around`注解的方法需要接收一个`TargetMethod`类型的参数,返回一个值作为目标方法的返回值。`TargetMethod`类的方法如下:
|方法|说明|
|---|---|
|`MethodSignature getSignature()`|获取目标方法签名|
|`Object[] getParams()`|获取目标方法的原始参数数组|
|`Object invoke(Object... params)`|使用指定参数调用目标方法|
|`Object invokeWithOriginalParams()`|使用原始参数调用目标方法|
目标方法:
```java
public String target(int a, String b) {
...
}
```
环绕增强方法:
```java
@Around
public String aroundTarget(TargetMethod targetMethod) {
// 获取目标方法的签名
MethodSignature signature = targetMethod.getSignature();
// 获取目标方法的原始参数
Object[] params = targetMethod.getParams();
// 自定义拦截操作,可以通过targetMethod的invoke方法来调用目标方法
// ...
// 返回值作为目标方法的最终返回值
return ...;
}
```
### @Replace
该注解用于替换目标方法的实现,被`@Replace`注解的方法必须与目标方法具有完全相同的签名。
目标方法:
```java
public String target(int a, String b) {
...
}
```
`Replace`增强方法:
```java
@Replace
public String replaceTarget(int a, String b) {
// 替换target方法的实现
// ...
}
```
### @AfterThrowing
该注解用于拦截目标方法抛出的异常。被`@AfterThrowing`注解的增强方法需要接收一个异常类作为参数,其返回值作为目标方法发生异常后的返回值。
目标方法:
```java
public String target(int a, String b) {
...
throw new MyException(...);
...
}
```
异常拦截方法:
```java
@AfterThrowing
public String handleException(MyException e) {
// 处理异常
// ...
return "exception";
}
```
## 方法匹配器注解
使用`@Filter`注解用来指定目标对象中哪些方法需要被增强。
如果不指定`@Filter`,则默认拦截所有方法。
下面的代码定义了一个前置增强,它作用于目标对象中所有方法名为`f1`、返回值类型为`int`、参数类型为`String`的方法:
```java
@Before
@Filter(name = "f1", returnType = int.class, parameterTypes = String.class)
public String[] g1(String s) {
return new String[]{s + "x"};
}
```
下面的代码对所有以`list`开头的方法做了统一异常处理:
```java
@Around
@Filter(pattern = "list(.*)")
public Object handleException(TargetMethod targetMethod) {
try {
return targetMethod.invokeWithOriginalParams();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
```
## 关于多重AOP代理
ByAOP支持用多个拦截器拦截同一个方法,这是利用多重AOP代理实现的。在默认情况下,这些拦截方法执行的顺序是随机的。
举个例子,假设有以下目标对象:
```java
public class A {
public void f() {
return ...;
}
}
```
以及以下增强类:
```java
public static class Advice {
@Around
@Filter(name = "f")
public String apple(TargetMethod targetMethod) {
System.out.println("before 1");
Object ret = targetMethod.invokeWithOriginalParams();
System.out.println("after 1");
return ret;
}
@Around
@Filter(name = "f")
public String cat(TargetMethod targetMethod) {
System.out.println("before 2");
Object ret = targetMethod.invokeWithOriginalParams();
System.out.println("after 2");
return ret;
}
@Around
@Filter(name = "f")
public String banana(TargetMethod targetMethod) {
System.out.println("before 3");
Object ret = targetMethod.invokeWithOriginalParams();
System.out.println("after 3");
return ret;
}
}
```
在增强类`Advice`中,为目标方法`f`指定了3个拦截方法,我们用下面的代码来创建一个AOP代理对象:
```java
A a = ByxAOP.getAopProxy(new A(), new Advice());
```
当我们调用`a.f()`时,`f`方法会被`Advice`中的三个拦截方法分别拦截,不过这些拦截方法的执行顺序是随机的,并不是按照拦截方法定义的顺序。在我的机器上,执行结果为:
```
before 1
before 3
before 2
after 2
after 3
after 1
```
如果需要指定多重代理的顺序,可以使用`@Order`注解,并传入一个用于指定顺序的整数。修改后的`Advice`类如下:
```java
public static class Advice {
@Around
@Filter(name = "f")
@Order(1)
public String apple(TargetMethod targetMethod) {
...
}
@Around
@Filter(name = "f")
@Order(2)
public String cat(TargetMethod targetMethod) {
...
}
@Around
@Filter(name = "f")
@Order(3)
public String banana(TargetMethod targetMethod) {
...
}
}
```
此时,如果再次执行上面的操作,就会发现,拦截方法执行的顺序与我们用`Order`声明的一致:
```
before 3
before 2
before 1
after 1
after 2
after 3
```
请注意:
* 如果不指定Order值,则Order值默认为1
* Order值小的拦截方法比Order值大的拦截方法先执行
* 如果多个拦截方法的Order值相等,则它们之间的执行顺序仍然是随机的