AOP

AOP

在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。


相关术语:

  • 横切关注点:诸如日志记录、权限校验等,这些影响多个模块,但是并不参与的模块的实现的定义。
  • 切面:模块化的横切逻辑单元,包含切入点和通知。
  • 目标:被代理的原始对象,包含核心业务逻辑。
  • 代理:由 Spring 生成的增强对象,包装目标对象,负责插入切面逻辑。
  • 连接点:程序执行过程中的具体节点。
  • 切入点:通过表达式筛选连接点的规则,决定哪些连接点会被切面增强。
/**
 * @auther macrozheng
 * @description 用于生产MBG的代码
 * @date 2018/4/26
 * @github https://github.com/macrozheng
 */
public class Generator {
    public static void main(String[] args) throws Exception {
        //MBG 执行过程中的警告信息
        List<String> warnings = new ArrayList<String>();
        //当生成的代码重复时,覆盖原代码
        boolean overwrite = true;
        //读取我们的 MBG 配置文件
        InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(is);
        is.close();

        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        //创建 MBG
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        //执行生成代码
        myBatisGenerator.generate(null);
        //输出警告信息
        for (String warning : warnings) {
            System.out.println(warning);
        }
    }
}

通知

Spring AOP 支持以下 5 种通知类型,按执行顺序排列:

通知类型执行时机使用注解是否可修改返回值
环绕包裹目标方法(必须手动调用目标方法)@Around
前置目标方法执行前@Before
后置目标方法执行后(无论是否异常)@After
返回目标方法正常返回后@AfterReturning
异常目标方法抛出异常后@AfterThrowing

切点表达式

定义哪些方法需要被切面增强。

语法结构:

execution(修饰符 返回类型 包名.类名.方法名(参数类型) 异常类型)

代理

AspectJ

完整的 AOP 框架,提供比 Spring AOP 更强大的功能。

实现方式:

  • 编译时织入(CTW):通过专用编译器(ajc)直接修改字节码。
  • 加载时织入(LTW):在类加载时通过 Java Agent 修改字节码。

功能特性:

  • 支持所有连接点(方法、构造器、字段访问等)。
  • 支持 call​(方法调用)和 execution​(方法执行)等更细粒度的切点。
  • 支持注解驱动和原生语法两种配置方式。

JDK 动态代理

Java 标准库提供的代理技术,基于接口实现.

  • 实现方式:
    • 使用 java.lang.reflect.Proxy​ 类生成代理对象。
    • 代理类实现目标接口,拦截所有接口方法调用。
  • 限制:
    • 只能代理接口中定义的方法。
    • 目标类必须实现至少一个接口。

CGLIB 动态代理

  • 定位:第三方库(已集成到 Spring 中),基于继承实现。
  • 实现方式:
    • 通过 ASM 字节码框架生成目标类的子类。
    • 重写父类方法实现拦截。
  • 优势:
    • 可代理无接口的普通类。
    • 方法调用效率高于 JDK 动态代理(通过 FastClass 机制避免反射)。