当前位置: 首页 > 后端技术 > Java

Spring(2)-AOP简介

时间:2023-04-01 14:01:34 Java

SpringAOP简介1.定义AOP即AspectOrientedProgramming,即面向切面的编程。那么什么是AOP?让我们回顾一下OOP:面向对象编程。作为一种面向对象的编程模型,OOP取得了巨大的成功。OOP的主要功能是数据封装、继承和多态。AOP是一种新的编程方法。它不同于OOP。OOP把系统看成是多个对象的交互。AOP将系统分解为不同的关注点,或称为切面(Aspect)。AOP主要用于解决程序开发中的一些系统级问题,如日志、事务、权限等待等。Struts2的拦截器设计是基于AOP的思想,这是一个经典的例子。2、AOP原理AOP要解决的问题是如何将切面编织到核心逻辑中,如何拦截调用方法,拦截前后进行安全检查、日志、事务等,相当于完成所有业务功能。在Java平台上,AOP的编织方式有以下三种:编译时:在编译时,编译器将切面调用编译成字节码。该方法需要定义新的关键字和扩展编译器。AspectJJava编译器扩展,使用关键字aspect实现织入;类加载器:当目标类加载到JVM中时,目标类的字节码通过特殊的类加载器重新“增强”;运行期:目标对象和切面为普通Java类,运行时动态织入通过JVM的动态代理功能或第三方库实现。最简单的方法是第三种。Spring的AOP实现是基于JVM的动态代理。由于JVM的动态代理要求必须实现接口,如果一个普通类没有业务接口,则需要通过第三方库如CGLIB或Javassist来实现。AOP技术看起来很神秘,但其实它本质上是一个动态代理,让我们把一些常用的功能,比如权限检查、日志、事务等,从各个业务方法中分离出来。需要指出的是,AOP对于解决具体的问题非常有用,比如事务管理,因为分散在各处的事务代码几乎完全相同,而且它们需要的参数(JDBCConnection)也是固定的。其他一些具体的问题,比如日志,就没那么容易实现了,因为日志虽然简单,但是在打印日志的时候往往需要捕获局部变量。如果使用AOP来实现日志,我们只能输出固定格式的日志。因此,使用AOP,它必须适合特定的场景。3.语法3.1基本概念Aspect:Aspect,即一个跨越多个核心逻辑的功能,或者系统关注点;Joinpoint:连接点,即定义在应用进程中的何处插入切面的执行;Pointcut:入口点,即连接点的集合;Advice:增强,指对特定连接点执行的动作;Introduction:引入,指的是动态地为一个已有的Java对象添加一个新的接口;编织:编织,是指将Aspects集成到程序的执行过程中;Interceptor:拦截器,是一种实现增强的方式;TargetObject:目标对象,是实际执行业务的核心逻辑对象;AOPProxy:AOP代理,是客户端持有对象引用后的增强,Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理。前者基于接口,后者基于子类,@Before只需要指定切入点表达式post通知(@After)在目标方法完成后增强,无论目标方法何时成功完成。@After可以指定一个入口点表达式返回通知(@AfterReturning)在目标方法正常完成后增强。@AfterReturning除了指定入口表达式外,还可以指定一个返回值参数名returning,代表目标方法的返回值异常通知(@AfterThrowing)主要用于处理程序中未处理的异常。除了指定入口点表达式,@AfterThrowing还可以指定一个抛出返回值形参名,可以用来访问目标方法包围通知(@Around)中抛出的异常对象包围通知,并进行增强目标方法完成前后的处理。周边通知是最重要的一类通知,比如事务、日志等都是周边通知。注意编程的核心是一个ProceedingJoinPoint3.3Enablemethodxml配置方法,在applicationContext.xml中配置如下一句:注解方法,添加@EnableAspectJAutoProxy@EnableAspectJAutoProxy@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]args){//dosomething}}4.示例4.1定义目标类publicclassMathCalculator{publicintdiv(intx,inty){System.out.println(x/y);返回x/y;}}4.2定义切面类并指定通知方法@AspectpublicclassLogAspects{@Pointcut("execution(intcom.test.tornesol.util.spring.spring_aop.MathCalculator.div(int,int))")publicvoidpointCut(){}@Before("com.test.tornesol.util.spring.spring_aop.LogAspects.pointCut()")publicvoidlogStart(JoinPointjoinPoint){System.out.println(joinPoint.getSignature().getName()+"除法运算,参数为:"+Arrays.asList(joinPoint.getArgs()));}@After("com.test.tornesol.util.spring.spring_aop.LogAspects.pointCut()")publicvoidlogEnd(){System.out.println("除法结束");}@AfterReturning(value="com.test.tornesol.util.spring.spring_aop.LogAspects.pointCut())",returning="result")publicvoidlogReturn2(JoinPointjoinPoint,Objectresult){System.out.println(joinPoint.getSignature().getName()+"除法返回"+结果);}@AfterThrowing(value="com.test.tornesol.util.spring.spring_aop.LogAspects.pointCut()",throwing="exception")publicvoidlogException(Exception异常){System.out.println("Divisionexception");}}注意:注意切面类添加@Aspect注解4.3添加配置类,注入目标类和切面类,开启AOP代理模式@Configuration@EnableAspectJAutoProxy//开启基于注解的AOP模式publicclassMainConfig{@BeanpublicMathCalculatormathCalculator(){返回新的MathCalculator();}@BeanpublicLogAspectslogAspects(){返回新的LogAspects();}}4.4测试输出publicclassAopDemo{staticpublicvoidmain(String[]args){AnnotationConfigApplicationContextcontext=newAnnotationConfigApplicationContext(MainConfig.class);context.getBean(MathCalculator.class).div(4,2);}}divdivisionrun,参数为:[4,2]2divisionenddivdivisionreturns25.AOP使用参考文档-廖雪峰官网(liaoxuefeng.com),廖雪峰的文档还不错,可以快速使用入门AOPAspectOrientedProgrammingWithSpring,Spring官方文档最权威最详细