什么是AOP?AOP(AspectOrientProgramming),直译就是面向方面的编程。AOP是一种编程思想,是对面向对象编程(OOP)的补充。面向对象编程将程序抽象为各个层次的对象,而面向方面编程将程序抽象为各个方面。为什么需要AOP?在实际开发中,我们应该都遇到过这样的场景:多个模块之间存在某段重复代码,我们通常是如何处理的?在传统的面向过程的编程中,我们也是将这段代码抽象成一个方法,然后在需要的地方调用这个方法,这样当这段代码需要修改的时候,我们只需要改这个方法即可。然而,要求总是在变化。有一天,增加了一个新的需求,需要做更多的修改。我们需要再抽象出一个方法,然后在需要的地方单独调用这个方法,否则就不需要这个方法了,我们仍然必须删除调用此方法的每个地方。其实我们可以用AOP来解决涉及到多处相同修改的问题。AOP的本质AOP的本质是通过AOP框架对业务组件的多个方法的源代码进行修改。看到这里,你应该明白了,AOP其实就是代理模式的一个典型应用。根据修改AOP框架源码的时机,可以分为两类:静态AOP实现,AOP框架在编译阶段修改程序的源码,生成一个静态AOP代理类(the生成的*.class文件已经被修改掉了,需要使用特定的编译器),比如AspectJ。动态AOP实现,AOP框架在运行时动态生成代理对象(JDK在内存中动态代理,或者CGlib动态生成AOP代理类),比如SpringAOP。AOPTerminologyAOP领域的一个术语:Advice:AOP框架中的增强处理。Advice描述了aspect何时被执行以及如何进行增强处理。连接点:连接点表示应用程序执行过程中可以插入切面的点。这个点可以是方法调用,也可以是抛出的异常。在SpringAOP中,连接点始终是方法调用。PointCut:可以插入增强处理的连接点。切面:切面是建议和切入点的组合。简介:简介允许我们向现有类添加新方法或属性。编织:对目标对象进行增强处理,创建增强对象。这个过程就是编织。这些术语在不同书籍中的翻译存在差异。关键是把理解和程序结合起来,理解每个术语的意思。第一个SpringAOP项目的新模块的名称取决于您的心情。这是sping-aop配置。在pom.xml文件中添加如下两个依赖:
的语法为:方法修饰装饰器(可省略)、方法返回类型、方法包名+方法名+方法参数类型列表全路径*/@Before(value="execution(publicvoidcom.javafirst.service.impl.SomeServiceImpl.doSome(java.lang.String,java.lang.Integer))")publicvoidaop_before(){System.out.println("执行原业务方法之前的逻辑,这里是自动代理要执行的代码function.");}}这里使用了注解@Aspect,也就是我们前面添加的依赖,也就是Spring提供的注解这里需要知道一个概念:切点表达式4、Spring核心配置文件applicationConext.xml代码如下: 方法定义:必须是public,必须有返回值,建议Object参数必须有和ProceedingJoinPoint*@paramjoinPoint@return*/@Around(value="execution(publicjava.lang.Stringcom.javafirst.service.impl.SomeServiceImpl.doWork(java.lang.String))")publicObjectaop_around(ProceedingJoinPointjoinPoint)throwsThrowable{System.out.println();System.out.println("我是@Around方法中的输出");//通过参数控制目标方法是否可以执行ProceedJoinPointObjectargs[]=joinPoint.getArgs();if(null!=args&&args.length>0){//执行目标方法if(null!=args[0]){joinPoint.proceed();return"你传入的参数是:"+args[0];}}return"我是@Around方法return的内容";}如果没有通过参数ProceedingJoinPoint执行目标方法,默认的目标方法不会执行;注意这里的输出语句和返回值执行逻辑,从而理解环绕通知。4.测试代码/**@Around可以在目标方法前后执行相关代码*/@TestpublicvoidtestAround(){Stringconfig="applicationContext.xml";ApplicationContextcontext=newClassPathXmlApplicationContext(config);SomeServicesomeService=(SomeService)context.getBean("someService");Stringresult=someService.doWork("李春刚");//Stringresult=someService.doWork(null);System.out.println("测试结果输出:"+result);}因此,您可以自己体验一下。通过改变参数,观察我们的通知代码执行逻辑,周围的通知不等于@Before+@AfterReturning。周围通知是一个_java培训机构,可以修改目标方法的返回值。@AfterThrowing(理解)在目标方法抛出异常后执行,如果没有抛出异常,则不执行(即如果目标方法本身try-catch异常,则通知方法不执行)。下面是一个例子:1.定义接口方法voiddoOrder(Integernum);为了验证结果,我们需要通过参数创建异常。为了方便简单易懂,这里我们在target方法中使用200/num。如果参数为0,则发生异常。2、实现类,即目标类的实现代码如下:@OverridepublicvoiddoOrder(Integernum){System.out.println("在目标方法中输出,如果参数为0,计算(2022/num)会抛出异常");num=2022/num;}3.切面类,定义通知方法代码:/**异常通知:目标方法抛出异常后调用,如果没有抛出异常,不会调用 Function:monitor目标方法的函数,如果出现异常,方便开发者定位问题修复bug*@paramex*/@AfterThrowing(value="execution(publicvoidcom.javafirst.service.impl.SomeServiceImpl.doOrder(java.lang.Integer))",throwing="ex")publicvoidaop_afterThrowing(Exceptionex){System.out.println("这句话会被只在目标方法异常时才输出!\nExceptionmessage:"+ex.getMessage());}以上是核心代码,大家可以自行测试。@After(理解)finalnotification:在目标方法返回或异常发生后调用,这个通知方法会一直被调用,适用于收尾工作,如:清除缓存,删除一些数据等。1.定义接口方法voidpayMoney(Stringaddress);如上,我们使用方法的参数来“创建异常”。2、实现类中代码:@OverridepublicvoidpayMoney(Stringaddress){System.out.println("目标方法第一句内容,输出参数:"+address);System.out.println("截取地址前三个单词:"+(address.substring(0,3)));//try{//System.out.println("截取地址前三个单词:"+(address.substring(0,3)));//}catch(Exceptionex){//System.out.println("目标方法有try-catch");//}System.out.println("目标方法异常后的输出语句。");}3。在切面类中定义通知代码:/**最终通知:必须执行,并且在目标方法之后*/@After(value="execution(..SomeServiceImpl.payMoney(..))")publicvoidaop_after(){System.out.println("\n切面类中的输出内容!");}结果大家可以自己验证一下。这个不难理解,类似于Java中的finally{intry-catch-finally}代码块,会一直执行。@Pointcut解决什么问题:我们在定义通知的时候,在每个方法上添加注解,注解中有切入点表达式。当我们定义的方法较多,需要更改路径或方法名等时,既麻烦又容易出错,所以@Pointcut注解解决了这个问题。使用方法:定义一个方法,方法体中不需要内容,在方法上加上@Pointcut注解,你应该想到了,注解也有一个value属性,那么表达式写在这里,如果以后想改,就改这个地方;而原来添加注解通知方法的地方只需要将表示流水的入口点的值改成这里定义的方法名(带括号)即可。我们来演示一下,以我们在文末学到的一段注解代码为例:@After(value="aop_pointcut()")notification:在切面类中输出内容!");}/**pre-notification,为了测试@Pointcut*/@Before(value="aop_pointcut()")publicvoidaop_before_pointcut(){System.out.println("aop_before_pointcut()前置通知:切面类输出内容!\n");}/**定义@Pointcut注解*/@Pointcut(value="execution(..SomeServiceImpl.payMoney(..))")privatevoidaop_pointcut(){}测试代码不用修改,直接看结果,这个其实也不难,和我们之前学习动态SQL时用到的include标签的作用是一样的。总结看到这里,我们已经学习完了Spring的两个核心内容,后面再学习两个内容:Spring集成MyBatis和Spring事务。Spring的面向切面编程是一种编程思想。其实并没有你想的那么难懂,尤其是有java编程基础的情况下。记住本文演示的5个通知注解,它们的用法,代码执行流程,那个阶段我们应该处理什么业务逻辑,后面会用到。文章来自codeniche