============== Spring面向切面 ============== 1 面向切面编程(Aspect Oriented Programming,AOP) 1.1 横切关注点 所谓横切关注点就是应用程序中许多地方都会用到的处理过程,比如: - 打印日志 - 事务管理 - 安全检查 - 缓存读写 - 错误处理 - 性能监测 - 自定义的通用业务规则 ... 横切关注点是相对于核心关注点而言的: - 核心关注点对应用而言是不可或缺的,是实现其核心功能的处理逻辑,如登录。 - 横切关注点对应用而言并非必需,与核心业务无关,在许多地方用到,如日志。 用户登录 下载文件 获取用户 提取文件 名和密码 存储路径 | | --错误处理----错误处理-- 横切关注点 | | 检查用户 检查文件 名和密码 是否存在 是否包含 | 非法字符 检查用户 | 是否具有 验证用户 下载该文 是否注册 件的权限 | | --打印日志----打印日志-- 横切关注点 | | 验证用户 读取文件 名和密码 内容打包 是否匹配 回传响应 | | 核心关注点 核心关注点 OOP的解决之道: - 将每个横切关注点的具体实现封装成独立的函数或者类 - 在所有需要使用横切关注点的地方调用该函数或类方法 - 横切关注点的实现只会在一个地方出现,复用好于复制 - 调用该函数或类方法的大量相似代码仍散布得到处都是 1.2 面向切面编程 所谓面向切面编程就是将业务逻辑中的横切关注点,以切面的方式剥离出来,并能够在指定的位置执行。 用户登录 下载文件 获取用户 提取文件 名和密码 存储路径 | | ---- 1 --------- 3 ----- 横切关注点 -> 错误处理切面 | | ______________ 检查用户 检查文件 |配置文件或注解| 名和密码 是否存在 |--------------| 是否包含 | Spring |1-错误处理切面| 非法字符 检查用户 <--------- |2-打印日志切面| | 是否具有 注入 |3-错误处理切面| 验证用户 下载该文 |4-打印日志切面| 是否注册 件的权限 |______________| | | ---- 2 --------- 4 ----- 横切关注点 -> 打印日志切面 | | 验证用户 读取文件 名和密码 内容打包 是否匹配 回传响应 | | 核心关注点 核心关注点 AOP的解决之道: - 将每个横切关注点的具体实现封装成独立的切面类 - 通过配置文件或注解指定在哪个位置执行哪个切面 - Spring根据配置文件或注解将切面注入到特定位置 - 程序代码中不会出现对横切关注点实现的显式调用 - 修改配置文件或注解即可修改切入位置、增删切面 AOP是通过预编译和运行期动态代理实现程序功能统一维护的技术。 AOP是OOP的延续,是函数式编程的衍生范式。 AOP通过对业务逻辑各部分的隔离,降低耦合度,强化可重用性,提高编程效率。 2 AOP的核心概念 连接点:程序执行过程中的特定位置,如方法调用、抛出异常等。 切入点:描述一个或多个连接点的表达式。 Advice:在特定连接点执行的代码。 切面:切入点+Advice 编织:根据切面中的切入点,找到对应的连接点,将Advice嵌(注)入其中。 3 简单的AOP示例 // 处理业务的Bean类 @Component public class HelloAOP { public void hello() { System.out.println("Hello AOP"); } } // 实现切面的Bean类 @Component @Aspect // <- 指明这是一个切面 public class Log { private final Calendar calendar = Calendar.getInstance(); private final SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss.SSS"); // 返回类型 包路径 类 方法 参数表 // *表示任意类| _____| | | |..表示0到n个 // 型包括void| / | | | |任意类型参数 @Around("execution(* cn.tedu.HelloAOP.hello(..))") public Object advice(ProceedingJoinPoint pjp) throws Throwable { time(); Object result = pjp.proceed(); // 实际调用HelloAOP time(); // 类的hello()方法 return result; } private void time() { calendar.setTimeInMillis(System.currentTimeMillis()); System.out.println(formatter.format(calendar.getTime())); } } // 配置类 @Configuration @ComponentScan(basePackages = "cn.tedu") @EnableAspectJAutoProxy // <- 启用Aspect注解 public class Config { } AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class); HelloAOP helloAOP = ctx.getBean("helloAOP", HelloAOP.class); helloAOP.hello(); // 实际调用Log类的advice()方法 08:49:54.028 Hello AOP 08:49:54.044 注意:使用切面需要在Maven中添加对spring-aspects的依赖。 ... org.springframework spring-aspects 5.3.9 例程:HelloAOP 4 领先的AOP技术 AspectJ - 最早的AOP技术,1995年推出第一个版本 - 一个完整的面向切面的编程语言 - 在字节码级别实现切面编织 Spring AOP - 基于Java的AOP框架,集成了AspectJ - 专注于通过AOP解决企业级应用问题 - 通过动态代理实现切面编织