二.AOP面向切面编程官方下载地址动力节点spring数据视频观看地址https://www.bilibili.com/video/BV1nz4y1d7uy2.1AOP(AspectOrientProgramming)概述。面向切面编程从动态的角度考虑程序运行过程的AOP底层,采用动态代理方式实现。使用了两种代理:JDK的动态代理和CGLIB的动态代理。AOP是动态代理的标准化。定义了动态代理的实现步骤和方法,方便开发者统一使用动态代理。Aspect:切面,给你的目标类添加的功能就是切面。与上面使用的日志一样,事务是方面。aspects的特点:一般都是非业务方法。Orient独立使用:facing,facingProgramming:Programming2.2相关术语1.Aspect:Aspect,意思是增强的功能,是完成某种功能的一堆代码。非业务功能,常见的切面功能包括日志、事务、统计信息、参数校验、权限验证,切面用于组织多个Advice,切面中定义了Advice,其实是对主要业务逻辑2的增强。JoinPoint:连接点,连接业务方法和切面的地方。对于某个类中的业务方法,程序执行过程中的某个特定点,比如方法调用,或者异常抛出。在SpringAOP中,连接点永远是一个方法调用3.Pointcut:入口点,指的是多个连接点方法的集合。多种方法。可以插入增强处理的连接点。简而言之,当一个连接点满足指定的要求时,连接点就会被增强,连接点就会成为一个入口点。4.Advice:AOP框架在特定入口点进行的增强处理。有“around”、“before”、“after”等类型的处理,可以表示切面函数的执行时间,入口点定义切入位置,通知定义切入时间5.target:目标对象,目标对象是指要增强的对象。即包含主要业务逻辑的类的对象2.3AspectJ2.3.1概述AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。主要包括两部分:一部分定义了如何表达和定义AOP编程的语法规范;另一部分是工具部分,包括编译、调试工具等,aspectJ框架实现aop有两种方式:使用xml配置文件:使用注解配置全局事务,我们在项目中一般使用注解来做aop功能,aspectj有5个注解@Before@AfterReturning@Around@AfterThrowing@After2.3.2AspectJ的切入点表达式表达式原型:execution(modifiers-pattern?ret-type-patterndeclaring-type-pattern?name-pattern(param-pattern)throws-pattern?)![/upload-images.jianshu.io/upload_images/27220553-f998cc2391d3017d.gif?imageMogr2/auto-orient/strip)相关解释:modifiers-pattern?访问类型ret-type-pattern返回值类型declaring-type-pattern?包名类名-pattern(param-pattern)方法名(参数类型和参数个数)throws-pattern抛出异常类型?表示可选部分以上表达式一共有4个部分执行(访问权限方法返回值方法声明(参数)异常类型)符号意义*0到多个任意字符。.在方法参数中使用,表示任意数量的参数;用在包名后面表示当前包和子包Path+用在类名后面表示当前类及其子类;用在接口后面表示当前接口及其实现类相关实例:execution(public(..)):anypublicmethodexecution(set(..)):anymethodexecution(com.xyz.service..*(..))以“set”开头:任何方法执行(com.xyz.service...(..)):在服务中定义e包或子包中任何类的任何方法当类名中出现“..”时,后面必须跟“”,表示包子包下的所有类package下所有packages(interface)中的所有方法都是执行的入口点(com.xyz.service.IAccountService+.(..)):IAccountService如果是接口,则为接口中的任意方法及其所有方法中的任意方法实现类;如果是类,则为本类及其子类中的任意方法execution(*joke(String,int))):所有joke(String,int)方法,joke()方法的第一个参数为String,第二个第一个参数是int;如果方法中的参数类型是java.lang包下的类,可以直接使用类名,否则必须使用全限定类名,如joke(java.util.List,int)2.3.3前言通知:@Before1。方法定义要求:publicmethodpublicmethod无返回值方法名自定义方法可以有参数也可以不带参数切面的功能执行位置:方法上方1.配置依赖org.springframeworkspring-context5.2.5.RELEASEorg.springframeworkspring-aspects<版本>5.2.5.RELEASE2。创建业务接口并实现类对象System.out.println("这是我的业务方法!!!");}}3.创建切面类:MyAspect.java@Aspect@Component("myAspect")publicclassMyAspect{/***在通知方法中指定参数:JoinPoint***/@Before(value="execution(void*..doSome(..))")publicvoidbefore(){System.out.println("这是前置通知");}}4.配置applicationContext.xml文件5.测试类调用@org.junit.Testpublicvoiddemo01(){Stringconfig="applicationContext.xml";ApplicationContextapp=newClassPathXmlApplicationContext(config);服务代理=(服务)app.getBean("myService");//输出当前类信息:com.sun.proxy.$Proxy17//证明它使用了JDK动态代理System.out.println(proxy.getClass().getName());代理.doSome();}2.3.4JoinPoint在通知方法中指定参数:JoinPointJoinPoint:businessmethod,添加切面函数的业务方法的功能:可以在通知方法中获取方法执行时的信息,如方法名称,以及方法的实际参数。如果需要切面函数中方法的信息,可以添加JoinPoint。JoinPoint参数的值由框架给定。它必须是第一个参数。不仅是pre-advice方法,它可以包含一个JoinPoint类型的参数,所有的notification方法都可以包含这个参数。MyAspect.java@Aspect@Component("myAspect")publicclassMyAspect{@Before(value="execution(void*..doSome(..))")publicvoidbefore(JoinPointjoinPoint){//获取方法定义System.out.println("方法签名(定义):"+joinPoint.getSignature());System.out.println("方法名:"+joinPoint.getSignature().getName());//获取方法的实际参数Object[]args=joinPoint.getArgs();for(Objectarg:args){System.out.println("参数:"+arg);}}System.out.println("这是一个预先通知!!!");}}测试类@org.junit.Testpublicvoiddemo01(){Stringconfig="applicationContext.xml";ApplicationContextapp=n新的ClassPathXmlApplicationContext(配置);服务代理=(Service)app.getBean("myService");proxy.doSome("张三",20);}打印结果2.3.5Postnotification:@AfterReturning在目标方法执行之后由于执行是在目标方法之后执行的,所以可以获得目标方法的返回值。注解的返回属性用于指定接收方法返回值的变量名。所以注解为post-notification的方法可以包含JoinPoint参数,另外还可以包含接收返回值的变量。变量最好是Object类型,因为目标方法的返回值可能是任意类型的业务方法@Component("myService2")publicclassSomeServiceImplimplementsSomeService{@OverridepublicvoiddoSome(){System.out.println("这是商业手段!!!");}@OverridepublicStringdoOther(Stringstr,inti){return"业务方法doOther的返回值!!!";}}设置通知1、注解的returning属性用于指定接收方法返回值的变量名。2、除了JoinPoint参数外,还可以包含用来接收返回值的变量。3、变量最好是Object类型。因为目标方法的返回值可能是任意类型4.方法定义要求:public方法public方法没有返回值方法名自定义方法有参数,推荐为Object,参数名自定义5.@AfterReturning:postnotificationvalue:Entrypointexpressionreturning:表示目标方法返回值的自定义变量。自定义变量名必须与通知方法的形参名相同。可以根据业务方法的返回值进行相应的操作@AfterReturning(value="execution(String*..doOther(..))",returning="res")publicvoidmyAftfor(Objectarg:args){System.out.println("目标方法参数:"+arg);("发布通知!!!");}测试类@Testpublicvoiddemo02(){Stringconfig="applicationContext.xml";ApplicationContextapp=newClassPathXmlApplicationContext(config);SomeServiceproxy=(SomeService)app.getBean("myService2");proxy.doOther("迪克",20);}2.3.6环绕通知:@Around在目标方法执行前后执行标注为环绕增强的方法,返回值标注为环绕增强的方法要有返回值,Object类型。并且该方法可以包含一个ProceedingJoinPoint类型的参数接口ProceedingJoinPoint,它有一个proceed()方法用于执行目标方法。如果目标方法有返回值,则该方法的返回值就是目标方法的返回值。最后,环绕增强方法返回它的返回值。这个增强方法实际上拦截了目标方法1的执行切面类。周围通知方法的定义格式:public必须有返回值,推荐使用Object方法名。自定义方法有参数,固定参数ProceedingJoinPoint2。特点是在目标方法中,前后台都可以增强功能,控制目标方法是否被调用执行,修改原目标方法的执行结果,影响最终的调用结果。这是最强大的通知。3.环绕通知相当于jdk动态代理的InvocationHandler接口4.参数:ProceedingJoinPoint相当于Method,用于执行目标方法5.返回值:为目标方法的执行结果,可以修改6.周边通知:经常做事务,在目标方法之前启动事务,执行目标方法,在目标方法中执行目标方法然后提交事务@Around(value="execution(String*..do(..))")publicObjectmyAround(ProceedingJoinPointp)throwsThrowable{Objectresult=null;//前置功能增强System.out.println("前置功能增强!!");//等同于method.invoke();对象结果=doFirst();结果=p.proceed();//后置功能增强System.out.println("后置功能增强");返回结果;}测试类@Testpublicvoiddemo01(){ApplicationContextapp=newClassPathXmlApplicationContext("applicationContext.xml");SomeServiceproxy=(SomeService)app.getBean("Service3");Stringultresult=proxy.doFirst("迪克",99);//输出返回结果System.out.println(结果);}2.3.7异常通知:@AfterThrowing在目标方法抛出异常后执行。该注解的throwing属性用于指定发生的异常类对象。注解为异常通知的方法可以包含一个参数Throwable,参数名称为throwing指定的名称,表示异常对象业务方法@OverridepublicvoiddoSecond(){System.out.println("执行业务方法doSecond()"+(10/0));}切面类1.异常通知方法定义格式:访问权限public无返回值方法名自定义方法有Exception,也可以使用JoinPoint2。@AfterThrowing:异常通知属性:取值入口点表达式throwinng自定义变量,表示目标方法抛出异常对象,变量名必须与方法的参数名相同。特点:当目标方法抛出异常时,可以作为异常监控程序,监控目标方法执行时是否发生异常。如果有异常,可以发邮件和短信通知System.out.println("异常通知:方法发生异常时,执行:"+ex.getMessage());//发送邮件,短信,通知开发者}2.3.8最终通知:@After不管目标方法是否抛出异常,这个增强都会被业务方法执行@OverridepublicvoiddoThird(){System.out.println("执行业务方法doThird()");}切面类1.最终通知定义格式:访问权限public无返回值方法名自定义方法无参数,但可以使用JoinPoint2。@After:最终的通知特性会一直在target方法之后执行//相当于下面的执行方法try{SomeServiceImpl.doThird(..)}catch(Exceptione){}finally{myAfter()}@After(value="execution(**..SomeServiceImpl.doThird(..))")SystempublicvoidmyAfter(){.out.println("执行最后的通知,一直执行的代码");//一般做资源清理工作}2.3.9@Pointcut定义入口点,当多个通知增强方法使用同一个执行入口点时,表达式的编写和维护比较麻烦;AspectJ提供@Pointcut注解来定义执行切入点表达式。在方法上注解@Pointcut,以后所有执行的value属性值都可以使用方法名作为pointcut,代表@Pointcut定义的切入点。这种使用@Pointcut注解的方法一般使用私有标识方法,即没有实际作用的方法切面类1.@Pointcut:定义和管理切入点。如果你的项目中有多个重复的切入点表达式,你可以复用。2.特点:当使用@Pointcut定义上面的一个方法时,这个方法的名字就是切入点表达式的别名。在其他通知中,value属性可以使用这个方法名代替切入点表达式@After(value="mypt()")publicvoidmyAfter(){System.out.println("执行最后一个通知,将要执行的代码总是被执行");//一般做资源清理。}@Before(value="mypt()")publicvoidmyBefore(){System.out.println("预通知,在目标方法之前执行");}@Pointcut(value="execution(**..SomeServiceImpl.doThird(..))")privatevoidmypt(){//不需要代码,}2.4代理替换如果目标类有接口,jdk动态代理默认使用;如果目标类没有接口,则使用CGlib动态代理如果代理想让有接口的目标类使用CGlib代理方法,需要如下配置文件