本文记录了苍穹外卖项目第三天的学习内容,重点介绍了 AOP 切面编程、菜品管理模块开发以及代码优化等核心技术。

这里主要知识点是AOP 切面编程思想,在这个思想中,用了三个常用注解。
核心思想: 把所有需要使用到修改公共字段的方法通过拦截器进行拦截,再通过反射进行赋值。
业务场景 在之前的项目开发中,每次创建和修改数据时都要重复设置修改时间、修改人等字段。这些字段属于公共字段,基于DRY 原则(Don’t Repeat Yourself),需要优化大量相似的代码,避免代码冗余。
优化前的问题:

解决思路
把所有需要使用到修改公共字段的方法通过拦截器进行拦截,再通过反射进行赋值。同时自定义注解,被该注解标记的方法会被拦截器拦截。
实现流程
@AutoFill@Target(ElementType.METHOD) // 只能标注在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时保留,可通过反射获取
public @interface AutoFill {
OperationType value(); // 指定操作类型:INSERT 或 UPDATE
}public enum OperationType {
UPDATE, // 更新操作
INSERT // 插入操作
}

@AutoFill,进行填充
@Mapper
public interface EmployeeMapper {
// 新增员工 - 自动填充创建时间和创建人
@AutoFill(value = OperationType.INSERT)
@Insert("insert into employee (...) values (...)")
void save(Employee employee);
// 更新员工 - 自动填充更新时间和更新人
@AutoFill(value = OperationType.UPDATE)
void update(Employee employee);
}方案优点 AOP 切面思想使得我们在不改变核心功能的情况下,大大减少了代码复用,同时字段填充集中处理,更加易于维护,更加简洁,具有可读性。 这种设计体现了 AOP 核心价值:将横切关注点从主业务逻辑中分离,提高代码的可维护性和复用性
@Pointcut 是 AOP 中的切入点注解,用于定义在哪些地方应用切面逻辑。
项目使用场景
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut(){}execution(* com.sky.mapper.*.*(..)):匹配所有 mapper 包下的方法
*:返回类型通配符
com.sky.mapper.*:mapper 包下的所有类
.*(..):所有方法,… 表示任意参数
&& @annotation(com.sky.annotation.AutoFill):且方法上必须有@AutoFill 注解
常见使用场景
// 1. 方法执行
@Pointcut("execution(* com.sky.service.*.*(..))")
// 2. 注解匹配
@Pointcut("@annotation(com.sky.annotation.AutoFill)")
// 3. 包匹配
@Pointcut("within(com.sky.mapper.*)")
// 4. 参数匹配
@Pointcut("args(java.lang.String)")
// 5. 组合表达式
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")@Target 是 Java 注解中的元注解,主要作用是约束注解应用于什么地方。
作用范围 | 说明 |
|---|---|
ElementType.TYPE | 接口、类、枚举、注解 |
ElementType.FIELD | 字段、枚举的常量 |
ElementType.METHOD | 方法 |
ElementType.PARAMETER | 方法参数 |
ElementType.CONSTRUCTOR | 构造函数 |
ElementType.LOCAL_VARIABLE | 局部变量 |
ElementType.ANNOTATION_TYPE | 注解 |
ElementType.PACKAGE | 包,用于记录 java 文件的 package 信息 |
使用示例
// 只能标注在方法上
@Target(ElementType.METHOD)
public @interface MethodAnnotation {}
// 可以标注在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ClassAndMethodAnnotation {}
// 可以标注在任何地方
@Target(ElementType.ANNOTATION_TYPE)
public @interface AnywhereAnnotation {}@Retention 用于指定注解的生命周期,即注解在什么时候有效。
生命周期 | 说明 | 应用场景 |
|---|---|---|
RetentionPolicy.SOURCE | 注解仅保留在源代码中,编译后消失 | 主要用于检查性操作,如@Override、@SuppressWarnings |
RetentionPolicy.CLASS | 注解保留在 class 文件中,运行时不可见 | 一般用于预处理操作,如 ButterKnife |
RetentionPolicy.RUNTIME | 注解保存在 class 文件中,运行时也存在 | 用于需要动态获取注解信息 |
使用示例
// 1. SOURCE - 源码阶段
@Retention(RetentionPolicy.SOURCE)
public @interface SourceAnnotation {}
// 作用:编译时检查,如@Override、@SuppressWarnings
// 2. CLASS - 编译阶段
@Retention(RetentionPolicy.CLASS)
public @interface ClassAnnotation {}
// 作用:编译时处理,如字节码增强
// 3. RUNTIME - 运行时阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeAnnotation {}
// 作用:运行时通过反射获取,如@AutoFill这三个注解在 AOP 中扮演不同角色: @Pointcut:定义"在哪里"应用切面逻辑 @Target:定义注解"可以标注在哪里" @Retention:定义注解"在什么时候有效" 它们协同工作,实现了声明式的 AOP 编程,让代码更加简洁和易维护。
逻辑外键是指不在数据库层级强制约束的外键关系,通常通过应用程序或业务逻辑来维护和实现,而不是依赖数据库的外键约束机制。
应用场景 在数据库表设计中,逻辑外键只表示表之间的关系,但没有显式的定义外键约束。逻辑外键的完整性是通过应用层(如代码、业务规则)来保证的。
在以前,我们在程序代码中直接使用固定值,而非采用动态数据的方式。 在这样情况下,他的执行效率高,但是可维护性差,灵活性低,不便于管理与修改。

在这样情况下,我们可以使用常量类进行存储。
将数据从代码中抽离出来,通过常量、配置文件、数据库等方式进行管理。

常量类的优点是便于管理,可维护性强,灵活性高

本文为苍穹外卖项目学习笔记,持续更新中…
如果我的内容对你有帮助,希望可以收获你的点赞、评论、收藏。