整个Query系统可以分成三层。最顶层的是Query,中间是AbstractQuery、类似TaskQuery特定化的某个Query,最底层是类似TaskQueryImpl一样的具体实现类。
Query中定义的是查询的最基本操作排序、返回列表、返回个数、分页。
AbstractQuery实现Query的方法,但是它无法完全实现,主要是定义一个模板方法,留一个未实现的钩子方法给最底层的实现类来实现。
最底层的就以TaskQueryImpl举例说明,实现AbstractQuery中的executeList()和executeCount()方法,还Task相关的中间层的方法。
AbstractVariableQueryImpl完了再写
所有的CRUD最后的操作会送到对应的Manager中。
以Task举例,最后的命令执行会到TaskEntityManagerImpl中,TaskEntityManagerImpl聚合了TaskDataManager,具体的执行会通过TaskDataManager的子类MybatisTaskDataManager来实现,而MybatisTaskDataManager的做法是通过父类AbstractDataManager的getDbSqlSession()方法获取到DbSqlSession来进行最后的操作。
DbSqlSession是在放在CommandContext中的,最后是通过AbstractManager中的getSession获取的,
这玩儿可以理解成成分层设计,就像web项目中的service层和dao层。

在Spring Boot应用中,可以使用**AOP(Aspect-Oriented Programming)**来实现所有方法在执行前和执行后自动打印日志。Spring AOP允许你通过编写切面(Aspect)来拦截方法调用,执行一些额外的操作,比如打印日志。
下面是一个完整的实现步骤,展示如何使用SLF4J结合Spring AOP来实现这一功能。
首先,确保你在pom.xml中已经包含了Spring AOP和SLF4J的依赖:
<dependencies>
<!-- SLF4J日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Spring AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>创建一个LoggingAspect类,在这个类中定义执行前后的日志逻辑。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义日志记录器
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// 定义前置通知,方法执行前调用
@Before("execution(* com.example.yourpackage..*(..))") // 替换为你的包路径
public void logBeforeMethodExecution(JoinPoint joinPoint) {
// 获取方法名称并打印日志
String methodName = joinPoint.getSignature().getName();
logger.info("Method {} is about to be executed", methodName);
}
// 定义后置通知,方法执行后调用
@AfterReturning(pointcut = "execution(* com.example.yourpackage..*(..))", returning = "result")
public void logAfterMethodExecution(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
logger.info("Method {} executed successfully with result: {}", methodName, result);
}
// 如果你还想记录异常情况,可以使用@AfterThrowing
@After("execution(* com.example.yourpackage..*(..))")
public void logAfterMethodThrows(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
logger.info("Method {} threw an exception", methodName);
}
}@Aspect: 表示该类是一个切面类。@Component: 将该类声明为Spring Bean,以便自动注入。@Before: 在方法执行前运行,可以在这里打印方法名称。@AfterReturning: 在方法成功执行并返回后运行,可以在这里打印方法返回结果。execution(..): 这是切点表达式,表示要拦截的包路径和方法,com.example.yourpackage..*(..)表示拦截该包下的所有方法。
在Spring Boot应用中,Spring AOP默认是启用的,如果你已经添加了spring-boot-starter-aop依赖,Spring会自动扫描并启用切面。如果没有启用,可以通过配置类或注解手动启用:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy // 启用AspectJ自动代理
public class YourSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(YourSpringBootApplication.class, args);
}
}当你运行应用程序并调用任何被拦截的方法时,日志会自动打印:
- 在方法执行之前,打印"Method [methodName] is about to be executed"
- 在方法执行成功并返回结果后,打印"Method [methodName] executed successfully with result: [result]"
你可以根据需要扩展日志功能,例如:
- 记录方法的入参 (
joinPoint.getArgs()) - 记录执行时间 (
System.currentTimeMillis()) - 处理异常日志 (
@AfterThrowing)
这是最常见的做法之一,可以为项目中的所有方法执行提供统一的日志记录。如果有特定的方法或类需要跳过日志记录,可以进一步调整切点表达式。

