作者:djw | 来源:互联网 | 2024-11-04 17:23
面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。SpringAOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。
AOP[面向切面编程] 1.什么是AOP? AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。 通常情况下一个系统/软件的需求有2种: 1.业务需求:实现具体某一个业务逻辑功能的实现过程。【添加,删除,修改,查询等等】 2.系统需求:在整个系统运行的过程中帮助完善系统业务需求的功能【性能监视,事务管理,安全检查,缓存,日志记录等】 现在我们需要完成的动作就是在需要使用系统需求的位置能够快速的将系统需求植入给必要的业务需求功能中。 此时我们可以通过代理模式将系统需求功能快速的植入到业务需求功能中。 代理模式有静态代理和动态代理两种 静态代理由父子模式和兄弟模式--------传统纵向继承体系【大量代码重复性编写】 动态代理由JDK动态代理和CGLIB动态代理----横向抽取机制 由于JDK动态代理只能给实现过接口的java对象生成代理对象,所以也不会作为使用系统需求功能快速植入给必要的业务需求功能中的操作方式。 CGLIB动态代理,由于可以为任何java类提供代理对象,因此被选择成为AOP[面向切面编程]的底层实现。 CGLIB动态代理是Aop的底层实现。 2.AOP相关的概念 joinpoint(连接点):指那些被拦截到的点。在spring中指的可以被代理(增强)的方法。【业务类中的业务需求方法】 poingcut(切入点):对哪些连接点进行拦截的定义。在Spring中指的真正需要被代理(增强)的方法。 advice(通知/增强):指拦截到连接点之后要做的事情。真正增强的那些代码(逻辑)。 通知/增强分为: 前置通知,后置通知,异常通知,最终通知,环绕通知。 aspect(切面):是切入点和通知/增强的结合过程。 introduction(引介):一种特殊的通知在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些方法或者字段。 target(目标对象):代码的目标对象。 weaving(织入):把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入。而AspectJ采用编译期织入和类装在期织入。 proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
3.AOP[面向切面编程]的具体实现 重点:掌握切入点表达式的编写 下面给出一些通用切入点表达式的例子。 1.任意公共方法的执行: execution(public * (…)) 2.任何一个名字以“set”开始的方法的执行: execution( set*(…)) 3.AccountService接口定义的任意方法的执行: execution(* com.xyz.service.AccountService.(…)) 4.在service包中定义的任意方法的执行: execution( com.xyz.service.. (…)) 5.在service包或其子包中定义的任意方法的执行: execution(* com.xyz.service…. (…)) 6.在service包中的任意连接点(在Spring AOP中只是方法执行): within(com.xyz.service.) 7.在service包或其子包中的任意连接点(在Spring AOP中只是方法执行): within(com.xyz.service… ) 8.实现了AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行): this(com.xyz.service.AccountService) 'this’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。 9.实现AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行): target(com.xyz.service.AccountService) 'target’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。 10.任何一个只接受一个参数,并且运行时所传入的参数是Serializable 接口的连接点(在Spring AOP中只是方法执行) args(java.io.Serializable) 'args’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。 请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。 11.目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行) @target(org.springframework.transaction.annotation.Transactional) '@target’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 12.任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行): @within(org.springframework.transaction.annotation.Transactional) '@within’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 13.任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行) @annotation(org.springframework.transaction.annotation.Transactional) '@annotation’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 14.任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified 注解的连接点(在Spring AOP中只是方法执行) @args(com.xyz.security.Classified) ‘@args’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 15任何一个在名为’tradeService’的Spring bean之上的连接点 (在Spring AOP中只是方法执行): bean(tradeService) 16.任何一个在名字匹配通配符表达式’*Service’的Spring bean之上的连接点 (在Spring AOP中只是方法执行): bean(*Service) 例如:
com.wangxing.spring.bean StudentBean public void insertStudent(); public void insertStudent(Student); PersonBean public void insertPerson(); public void insertPerson(Student); public void deletePerson(int perid); execution(com.wangxing.spring.bean.*.*(..)) execution(com.wangxing.spring.bean.StudentBean.*(..)) execution(com.wangxing.spring.bean.*.insert*(..))
1.基于XML文件【Spring配置文件】的AOP实现
org.springframework spring-context 5.1.5.RELEASE org.springframework spring-context-support 5.1.5.RELEASE org.springframework spring-aspects 5.1.5.RELEASE package com.wangxing.spring.service; //业务需求类 public class UserService {//添加用户信息的业务方法public void insertUser(){System.out.println("添加用户信息的业务方法");}//修改用户信息的业务方法public void updateUser(){System.out.println("修改用户信息的业务方法");//int a=10/0;}//删除用户信息的业务方法public void deleteUser(){System.out.println("删除用户信息的业务方法");}//查询用户信息的业务方法public void selectUser(){System.out.println("查询用户信息的业务方法");} }package com.wangxing.spring.service; import org.aspectj.lang.ProceedingJoinPoint; //增强类/通知类 public class MyAvice {//系统需求功能实现方法public void saveLog(){System.out.println("记录执行日志");}//执行环绕通知的系统需求功能实现方法public void testAround(ProceedingJoinPoint joinPoint) throws Throwable{saveLog();joinPoint.proceed(); // 调用真正的业务方法saveLog();} }
2.基于注解的Aop实现
org.springframework spring-context 5.1.5.RELEASE org.springframework spring-context-support 5.1.5.RELEASE org.springframework spring-aspects 5.1.5.RELEASE package com.wangxing.spring.service;import org.springframework.stereotype.Component;//业务类 @Component("personService") public class PersonService {public void insertPerson(){System.out.println("添加个人信息的业务方法");}public void updatePerson(){System.out.println("修改个人信息的业务方法");//int a=10/0;}public void deletePerson(){System.out.println("删除个人信息的业务方法");}public void selectPerson(){System.out.println("查询个人信息的业务方法");} }package com.wangxing.spring.service; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;//增强类 //@Aspect,表示这个系统需求类是一个切面 @Component @Aspect public class MyAvice {//系统需求功能实现方法//@Before("execution(* com.wangxing.spring.service.PersonService.selectPerson())")//@AfterReturning("execution(* com.wangxing.spring.service.PersonService.deletePerson())")//@AfterThrowing("execution(* com.wangxing.spring.service.PersonService.updatePerson())")@After("execution(* com.wangxing.spring.service.PersonService.updatePerson())")public void saveLog(){System.out.println("记录执行日志");}//执行环绕通知的系统需求功能实现方法@Around("execution(* com.wangxing.spring.service.PersonService.insertPerson())")public void testAround(ProceedingJoinPoint joinPoint) throws Throwable{saveLog();joinPoint.proceed(); // 调用真正的业务方法saveLog();} }