独立使用 JFinal Aop
添加 jfinal-aop 依赖
jfinal-aop 可以独立使用,
- 你可以在其他项目中使用 jfinal-aop
- 你也可以在 Android 工程中使用 jfinal-aop
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>jfinal-aop</artifactId>
<version>${jfinal-aop.version}</version>
</dependency>
使用拦截器
如何在 Java 应用程序中使用 JFinal AOP
(面向切面编程)库来实现拦截器功能。 这个演示主要涉及三个部分:目标类(Cat
),拦截器类(Aspect1
),以及主测试类(CatMainTest
)。
1. 目标类(Cat)
Cat
类代表了一个简单的实体,包含一个方法 eat()
,该方法通过 @Before
注解与 Aspect1
类关联,表示在调用 eat()
方法前,应先执行 Aspect1
拦截器的逻辑。
import com.litongjava.jfinal.aop.Before;
public class Cat {
@Before(Aspect1.class)
public String eat() {
return "eat chat";
}
}
2. 拦截器类(Aspect1)
Aspect1
实现了 Interceptor
接口,提供了 intercept
方法。该方法在与之关联的方法(本例中为 Cat.eat
)执行前后被调用。
在 intercept
方法内部,可以访问被调用方法的详细信息(如方法名称、参数等),并在方法执行前后执行自定义逻辑。本例中,intercept
方法的实现做了以下几件事:
- 打印日志,显示拦截器被调用前后的信息("Before Aspect1 invoking" 和 "After Aspect1 invoking")。
- 使用
Invocation
对象获取被拦截方法的相关信息(方法本身、方法名、参数、目标对象)并打印。 - 执行实际的方法调用(
invocation.invoke()
)。 - 修改返回值为
"set new value"
。
import com.litongjava.jfinal.aop.Interceptor;
import com.litongjava.jfinal.aop.Invocation;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.util.Arrays;
@Slf4j
public class Aspect1 implements Interceptor {
@Override
public void intercept(Invocation invocation) {
System.out.println("Before Aspect1 invoking");
Method method = invocation.getMethod();
String methodName = invocation.getMethodName();
Object[] args = invocation.getArgs();
Object target = invocation.getTarget();
log.info("method:{}", method);
log.info("methodName:{}", methodName);
log.info("args:{}", Arrays.toString(args));
log.info("target:{}", target);
Object invoke = invocation.invoke();
invocation.setReturnValue("set new value");
log.info("invoke:{}", invoke);
System.out.println("After Aspect1 invoking");
}
}
3. 主测试类(CatMainTest)
在 CatMainTest
类中,通过 Aop.get(Cat.class)
获取 Cat
类的代理实例。当调用 eat
方法时,会先执行 Aspect1
中的拦截器逻辑,然后执行 eat
方法本身。
最终,由于拦截器中修改了返回值(将其设置为 "set new value"
),因此即使原始 eat
方法返回的是 "eat chat"
,打印出的结果也是 "set new value"
。
package com.issues01;
import com.litongjava.jfinal.aop.Aop;
public class CatMainTest {
public static void main(String[] args) {
new CatMainTest().index();
}
public void index() {
String javaVersion = System.getProperty("java.version");
System.out.println("java-version:" + javaVersion);
Cat cat = Aop.get(Cat.class);
String eat = cat.eat();
System.out.println("result:" + eat);
}
}
日志信息
java-version:1.8.0_121
Before Aspect1 invoking
2024-01-30 21:30:43.615 [main] INFO c.i.Aspect1.intercept:21 - method:public java.lang.String com.issues01.Cat.eat()
2024-01-30 21:30:43.617 [main] INFO c.i.Aspect1.intercept:22 - methodName:eat
2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:23 - args:[]
2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:24 - target:com.issues01.Cat$$EnhancerByJFinal@661972b0
2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:27 - invoke:eat chat
After Aspect1 invoking
result:set new value
日志信息展示了日志信息展示了整个拦截过程的细节和执行流程:
输出 Java 版本:显示正在使用的 Java 版本。
java-version:1.8.0_121
拦截器前的打印信息:显示拦截器开始工作之前的日志。
Before Aspect1 invoking
拦截器内部的日志信息:显示拦截器内部获取的方法信息和目标对象信息。这部分信息由拦截器
Aspect1
中的代码产生:- 方法名、方法参数、目标对象实例和调用的结果("eat chat")被打印。
- 这些信息主要用于调试和记录目标方法的调用情况。
2024-01-30 21:30:43.615 [main] INFO c.i.Aspect1.intercept:21 - method:public java.lang.String com.issues01.Cat.eat() 2024-01-30 21:30:43.617 [main] INFO c.i.Aspect1.intercept:22 - methodName:eat 2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:23 - args:[] 2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:24 - target:com.issues01.Cat$$EnhancerByJFinal@661972b0 2024-01-30 21:30:43.618 [main] INFO c.i.Aspect1.intercept:27 - invoke:eat chat
拦截器后的打印信息:显示拦截器完成工作之后的日志。
After Aspect1 invoking
最终结果:尽管原始
Cat.eat()
方法返回的是"eat chat"
,但由于在拦截器Aspect1
中修改了返回值,所以最终打印的结果是"set new value"
。result:set new value
这个过程体现了 AOP(面向切面编程)的典型用例,即在不修改原有业务逻辑的情况下,能够对方法调用进行拦截,并执行额外的处理逻辑,比如日志记录、性能统计、安全控制等。在这个例子中,拦截器 Aspect1
被用来修改方法的返回值,展示了 AOP 的强大能力。
类扫描和自动注入
使用 JFinal AOP
库来实现类的扫描、自动注入(依赖注入),以及基于注解的服务定义和消费。
1. 接口定义(DemoService)
首先定义了一个接口 DemoService
,它声明了一个方法 Hello
。
public interface DemoService {
public String Hello();
}
2. 服务实现(DemoServiceImpl)
然后,实现了上述接口 DemoService
。使用 @AService
注解标记该类,让 AOP 容器能够识别和管理它。这种方式通常用于在应用程序中定义服务组件。
import com.litongjava.jfinal.aop.annotation.AService;
@AService
public class DemoServiceImpl implements DemoService {
public String Hello(){
return "Hello";
}
}
3. 控制器定义(DemoController)
接下来定义了一个控制器类 DemoController
。使用 @AController
注解标记该类,表明它是一个 MVC 架构中的控制器组件。在该类中,通过 @AAutowired
注解自动注入了 DemoService
的实例 demoService
。然后定义了一个方法 hello()
,调用 demoService.Hello()
来返回结果。
import com.litongjava.jfinal.aop.annotation.AAutowired;
import com.litongjava.jfinal.aop.annotation.AController;
@AController
public class DemoController {
@AAutowired
private DemoService demoService;
public String hello() {
return demoService.Hello();
}
}
4. 应用入口(DemoApp)
最后,在应用入口 DemoApp
中,使用 JFinal AOP
的 Aop
工具类来扫描、初始化注解,并获取 DemoController
的实例。然后调用 demoController.hello()
方法,打印其返回值。
import java.util.List;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.aop.annotation.AComponentScan;
@AComponentScan
public class DemoApp {
public static void main(String[] args) throws Exception {
List<Class<?>> scannedClasses = Aop.scan(DemoApp.class);
Aop.initAnnotation(scannedClasses);
DemoController demoController = Aop.get(DemoController.class);
String hello = demoController.hello();
System.out.println(hello);
//关闭容器
Aop.close();
}
}
在 main
方法中,Aop.scan(DemoApp.class)
扫描带有 @AComponentScan
注解的类和其包下的所有类。然后 Aop.initAnnotation(scannedClasses)
初始化扫描到的类的注解。通过 Aop.get(DemoController.class)
获取 DemoController
的代理实例,并调用其 hello()
方法。最后,通过 Aop.close()
关闭 AOP 容器。
输出(output)
Hello
这是调用 demoController.hello()
方法的结果,显示服务正常工作,依赖注入和类扫描也都按预期工作。
这段代码通过使用 JFinal AOP` 库,演示了如何在 Java 应用程序中实现类扫描、自动注入和基于注解的服务定义与消费。