文章目录

  • 一、前言
  • 二、AOP基础知识
    • 2.1 AOP
      • 2.1.1 引子:AOP,AOP是什么?
      • 2.1.2 使用对比的方式理解AOP——AOP与OOP
      • 2.1.3 使用对比的方式理解AOP——静态AOP与动态AOP
      • 2.1.4 使用对比的方式理解AOP——Spring IOC与Spring AOP
    • 2.2 AOP的项目需求
    • 2.3 AOP的相关概念(用Spring AOP来解释AOP的相关概念)
  • 三、静态AOP实现:AspectJ AOP
    • 3.1 AspectJ AOP
    • 3.2 AspectJ AOP实践
      • 3.2.1 目录结构
      • 3.2.2 两个实体类和启动类
      • 3.2.3 三个切面
      • 3.2.4 运行结果
  • 四、动态AOP实现:Spring AOP
    • 4.1 Spring AOP基本知识
      • 4.1.1 Spring IOC实现Spring AOP
      • 4.1.2 Spring AOP代理
      • 4.1.3 Spring AOP是一种动态AOP
      • 4.1.4 Spring AOP连接点
      • 4.1.5 Spring AOP实现
    • 4.2 Spring AOP实践:注解方式实现
      • 4.2.1 目录结构
      • 4.2.2 两个POJO类
      • 4.2.3 五个Aspect类
      • 4.2.4 配置文件applicationContext.xml
      • 4.2.5 启动类Test
      • 4.2.6 运行结果
    • 4.3 Spring AOP实践:XML配置文件方式实现
      • 4.3.1 目录结构
      • 4.3.2 两个POJO类
      • 4.3.3 三个Aspect类
      • 4.3.4 Spring配置文件appliationContext.xml
      • 4.3.5 Test启动类
      • 4.3.6 运行结果
  • 五、小结

一、前言

本文分为三个部分,分别介绍AOP基础知识,以AspectJ AOP为例介绍静态AOP,以Spring AOP为例介绍动态AOP,其中以Spring AOP为重点,全文从AOP到AspectJ AOP,再到Spring AOP。

二、AOP基础知识

2.1 AOP

2.1.1 引子:AOP,AOP是什么?

官方解释:
AOP英文全称Aspect Oriented Program,直译面向切面编程,通过预编译方式或运行期动态代理(根据具体使用何种方式划分静态AOP、动态AOP)实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性。

我的理解:
AOP像OOP一样,只是一种编程范式,AOP并没有规定说,实现AOP协议的代码,要用什么方式去实现,AOP和OOP一样只是一种编程思想,且看两种对比的方式理解AOP。

2.1.2 使用对比的方式理解AOP——AOP与OOP

用理解OOP(面向对象编程)的方式去理解AOP(面向切面编程)
OOP是一种软件开发思想,是以类为基本单位的;AOP是一种程序维护思想,是以方法为基本单位的。
OOP的特点是继承、多态和封装;AOP的特点是对方法增强(有装饰器模式的影子),有静态AOP和动态AOP两种。

2.1.3 使用对比的方式理解AOP——静态AOP与动态AOP

静态AOP:AOP框架在编译阶段对程序进行修改,即实现对目标类的增强,生成静态的AOP代理类(生成的*.class文件已经被修改,需要使用特定的编译器)。举例:AspectJ。 动态AOP:AOP框架在运行阶段动态生成AOP代理(在内存中以JDK动态代理或cglib动态地生成AOP代理类),以实现对目标对象的增强。举例:Spring AOP。

如下表:

AOP形式 举例 特点
编译时织入(即静态AOP) AspectJ 具有较好的性能,但需要特殊的编译器
运行时织入(即动态AOP) Spring AOP、JBoss 性能较差,纯Java代码实现,无需特殊编译器

所以,Spring中的AOP是一种动态AOP,在运行阶段动态生成AOP代理以实现对目标对象的增强。

2.1.4 使用对比的方式理解AOP——Spring IOC与Spring AOP

Spring IOC和Spring AOP都是Spring的功能点,但是两个特点之间存在联系。
Spring中的AOP代理由Spring的loC容器负责生成、管理,其依赖关系也由loC容器负责管理。因此,AOP代理可以直接使用容器中的其他Bean实例作为目标,这种关系可由loC容器的依赖注入提供。
Spring实现AOP的方法跟其他的框架不同,Spring并不是要提供最完整的AOP实现(尽管 Spring AOP有这个能力), Spring侧重于AOP实现和 Spring loc容器之间的整合,用于帮助解决企业级开发 中的常见问题。
因此, Spring的AOP通常和 Spring loc容器一起使用, Spring AOP从来没有打算通过提供一种全 面的AOP解决方案来与 Aspect竞争, Spring AOP采用基于代理的AOP实现方案,而 AspectJ则采用编译时增强的解决方案。

2.2 AOP的项目需求

现在假设系统中有三段完全相同的代码,这些代码通常会采用“复制”、“粘贴”的方式来完成,通过这种“复制”,“粘贴”的方式开发出来的软件示意图如图所示:

这种做法的不足之处在于如果有一天,上图中的深色代码段需要修改,那是不是要打开三个地方的代码进行修改?如果不是三个地方包含这段代码,而是100个地方,甚至是1000个地方包含这个代码段,那会是什么后果? 为了解决这个问题,通常会将图中所示的深色代码部分定义成一个方法,然后在三个代码段中分别调用该方法即可。在这种方式下,软件系统的结构示意图如图:

如果需要修改深色代码部分,只要修改一个地方即可,不管整个系统中有多少个地方调用了该方法,程序无须修改这些地方,只需修改被调用的方法即可—通过这种方式,大大降低了软件后期维护的复杂度,这就是AOP在项目开发中的实践使用

2.3 AOP的相关概念(用Spring AOP来解释AOP的相关概念)

AOP含义(基于AOP概念的AOP含义解释):在面向切面编程的思想里面,把功能分为核心业务功能和周边功能。 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务;所谓的周边功能,比如性能统计,日志,事务管理等等 。周边功能在Spring的面向切面编程AOP思想里,即被定义为切面,在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 “编织” 在一起,这个过程叫AOP。

AOP核心概念(一共8个)

1、横切关注点(Cross-cutting concern)名词, 对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

2、切面(aspect) 类是对物体特征的抽象,切面就是对横切关注点的抽象

3、连接点(joinpoint) 被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

4、切入点(pointcut) 对连接点进行拦截的定义,就是定义对哪些方法进行拦截,可以对一个类的所有方法进行拦截,也可以只拦截一个类以特定字符开头的方法

5、通知(advice) 所谓通知指的就是切面Aspect中对于横切关注点Cross-cutting concerns的具体实现代码,亦即拦截到连接点之后要执行的代码。通知分为前置@Before、后置@After、异常@AfterThrowing、最终@AfterRunning、环绕@Around通知五类,就是拦截到方法之后,在什么时机执行切面的代码.

附:AspectJ 支持 5 种类型的通知注解(这五种通知后面的Spring AOP代码中会一一演示):
@Before:前置通知, 在方法执行之前执行
@After: 后置通知,在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知,在方法抛出异常之后
@Around: 环绕通知,围绕着方法执行

6、目标对象(Target)名词,代理的目标对象。
7、织入(weave) 动词,将切面(aspect)应用到目标对象(Target)并导致代理对象创建的过程成为织入。
8、引入(introduction) 在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

三、静态AOP实现:AspectJ AOP

3.1 AspectJ AOP

为什么是AspectJ?
AspectJ是一个基于Java语言的AOP框架,提供了强大的AOP功能,后来的很多AOP框架都借鉴或接纳其中的一些思想,由于 Spring4.0的AOP与 Aspect进行了很好的集成,因此掌握 Aspect是学习Spring AOP的基础。
从Spring2.0开始, Spring AOP已经引入了对 AspectJ的支持,并允许直接使用 AspectJ进行AOP编程,而 Spring自身的 AOP API也努力与 AspectJ保持一致,因此,学习 Spring AOP就必然需要从 Aspect 开始,因为它是Java领域最流行的AOP解决方案,即使不用 Spring框架,也可以直接使用 Aspect进行AOP编程。

AspectJ简介
AspectJ是Java语言的一个AOP实现,其主要包括两个部分:一个部分定义了如何表达、定义AOP编程中的语法规范,通过这套语法规范,可以方便地用AOP来解决Java语言中存在的交叉关注点的问题:另一个部分是工具部分,包括编译器、调试工具等。
AspectJ是最早的、功能比较强大的AOP实现之一,对整套AOP机制都有较好的实现,很多其他的AOP实现,也借鉴或采纳了 AspectJ中的很多设计,在Java领域, Aspect中的很多语法结构基本上已成为AOP领域的标准。

3.2 AspectJ AOP实践

3.2.1 目录结构

如图:

3.2.2 两个实体类和启动类

代码:

package mypackage;/*** Created by 30292 on 2020/2/22.*/
public class Test {public static  void main(String[] args){Hello hello=new Hello();hello.foo();hello.addUser("张三","1000");World world=new World();world.bar();}
}
class Hello {public void foo(){System.out.println("执行Hello组件的foo()方法");}public int addUser(String name,String pass){System.out.println("执行Hello组件的addUser()添加用户:"+name);return 20;}
}
class World {public void bar(){System.out.println("执行World组件的bar()方法");}
}

3.2.3 三个切面

package mypackage;public aspect AuthAspect{before():execution(* mypackage.*.*(..)){System.out.println("before 模拟进行权限检查...");}
}
aspect LogAspect{after():execution(* mypackage.*.*(..)){System.out.println("after 模拟记录日志...");}
}aspect TxAspect{Object around():call(* mypackage.*.*(..)){System.out.println("around start模拟开启事务...");Object rvt=proceed();System.out.println("around finish模拟结束事务...");return rvt;
}
}

3.2.4 运行结果

运行结果如下(AspectJ和实际方法均有打印):

四、动态AOP实现:Spring AOP

Spring AOP采用基于代理的AOP实现方案,而AspectJ采用编译时增强的解决方案。

4.1 Spring AOP基本知识

4.1.1 Spring IOC实现Spring AOP

Spring中的AOP代理由Spring的loC容器负责生成、管理,其依赖关系也由loC容器负责管理。因此,AOP代理可以直接使用容器中的其他Bean实例作为目标,这种关系可由loC容器的依赖注入提供。
Spring实现AOP的方法跟其他的框架不同,Spring并不是要提供最完整的AOP实现(尽管 Spring AOP有这个能力), Spring侧重于AOP实现和 Spring loc容器之间的整合,用于帮助解决企业级开发 中的常见问题。
因此, Spring的AOP通常和 Spring loc容器一起使用, Spring AOP从来没有打算通过提供一种全 面的AOP解决方案来与 Aspect竞争, Spring AOP采用基于代理的AOP实现方案,而 AspectJ则采用 编译时增强的解决方案。

4.1.2 Spring AOP代理

Spring默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了。 Spring也可以使用cglib代理,在需要代理类而不是代理接口的时候, Spring会自动切换为使用cglib代理。但Spring推荐使用面向接口编程,因此业务对象通常都会实现一个或多个接口,此时默认将使用JDK动态代理,但也可强制使用cglib代理。

4.1.3 Spring AOP是一种动态AOP

Spring AOP是动态AOP,使用纯Java实现,不需要特定的编译工具, Spring AOP也不需要控制类装载器层次,因此它可以在所有的 Java Web容器或应用服务器中运行良好。

4.1.4 Spring AOP连接点

Spring目前仅支持将方法调用作为连接点( Joinpoint),如果需要把对成员变量的访向和更新也作为增强处理的连接点,则可以考虑使用 AspecJ。

4.1.5 Spring AOP实现

Spring2.0可以无缝地整合 Spring AOP,IOC和 AspectJ,使得所有的AOP应用完全融入基于 Spring 的框架中,这样的集成不会影响 Spring AOP API或者 AOP Alliance API, Spring AOP保持了向下兼容性 依然允许直接使用 Spring AOP API来完成AOP编程。

一旦掌握了上面AOP的相关概念,不难发现进行AOP编程其实是很简单的事情,纵观AOP编程, 其中需要程序员参与的只有三个部分。
(1)定义普通业务组件;
(2)定义切入点,一个切入点可能横切多个业务组件;
(3)定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作;
其中第一个部分是最平常不过的事情,所以无须额外说明。那么进行AOP编程的关键就是定义切入点定义增强处理。一旦定义了合适的切入点和增强处理,AOP框架将会自动生成AOP代理,而 AOP代理的方法大致有如下公式:
AOP代理的方法=增强处理+目标对象的方法
我们使用 AspectJ方式来定义切入点和增强处理,在这种方式下, Spring依然有如下两种选择来定 义切入点和增强处理:
(1)基于注解的“零配置”方式:使用@Aspect,@Pointcut等注解来标注切入点和增强处理,在4.2
(2)基于XML配置文件的管理方式:使用Spring配置文件来定义切入点和增强处理,在4.3

附:自动增强
自动增强,指的是Spring会判断一个或多个切面是否需要对指定的Bean进行增强,并据此自动生成相应的代理,从而使得增强处理在合适的时候被调用,整个过程对开发者来说是透明的,是自动的,所以是自动增强。

4.2 Spring AOP实践:注解方式实现

4.2.1 目录结构

4.2.2 两个POJO类

先看两个pojo类,很简单:

package com.pojo;import org.springframework.stereotype.Component;/*** Created by 30292 on 2020/2/21.*/
@Component("hello")
public class Hello {public void foo() {System.out.println("执行hello组件的foo()方法");}public void addUser(String name, String pass) {System.out.println("执行Hello组件的addUser添加用户:" + name);}public void _functionException(int orgin) {int a = orgin / 0;  //除数为0,制造异常}
}
package com.pojo;import org.springframework.stereotype.Component;/*** Created by 30292 on 2020/2/21.*/
@Component("world")
public class World {public void bar(){System.out.println("执行World组件的bar()方法");}
}

4.2.3 五个Aspect类

再看五个aspect类,描述了五种增强,使用注解的方式,分别是@Before @After @AfterReturning @AfterThrowing @Around

@Before

package com.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;import java.util.Arrays;@Aspect
public class BeforeAspect {  //定义一个切面   某类上面加上一个@Aspect注解,就变成了一个切面@Before("execution(* com.pojo.*.*(..))")public void beforeAspectFunction(JoinPoint joinPoint){System.out.println("这里是Before增强");System.out.println("Before增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("Before增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("Before增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}
}

@After

package com.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;import java.util.Arrays;@Aspect
public class AfterAspect {@After("execution(* com.pojo.*.*(..))")public void afterAspectFunction(JoinPoint joinPoint){System.out.println("这里是After增强");System.out.println("After增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("After增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("After增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}
}

@AfterReturning

package com.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;import java.util.Arrays;@Aspect
public class AfterReturningAspect {@AfterReturning(returning = "rvt", pointcut = "execution(* com.pojo.*.*(..))")public void afterReturningAspectFunction(JoinPoint joinPoint, Object rvt){System.out.println("这里是AfterReturning增强,打印目标方法返回值: "+rvt);System.out.println("AfterReturning增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("AfterReturning增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("AfterReturning增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}
}

@AfterThrowing

package com.aspect;import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;@Aspect
public class AfterThrowingAspect {@AfterThrowing(throwing = "ex",pointcut = "execution(* com.pojo.*.*(..))")public void afterThrowingAspectFunction(Throwable ex){System.out.println("这里是AfterThrowing增强处理,打印目标方法中抛出的异常: "+ex);}
}

@Around

package com.aspect;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;@Aspect
public class AroundAspect {@Around("execution(* com.pojo.*.*(..))")public Object aroundAspectFunction(ProceedingJoinPoint joinPoint) throws java.lang.Throwable {System.out.println("这里是Around增强");System.out.println("Around增强:执行目标方法之前,模拟开始事务...");Object[] args = joinPoint.getArgs();if (args != null && args.length > 1) {args[0] = "[增加的前缀]" + args[0];}Object rvt = joinPoint.proceed(args);System.out.println("Around增强:执行目标方法之后,模拟结束事务...");if (rvt != null && rvt instanceof Integer)rvt = (Integer) rvt * (Integer) rvt;return rvt;}
}

4.2.4 配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- 启用AspectJ支持--><aop:aspectj-autoproxy/><!--扫描pojo中的@Component注解 aspect中的@Aspect注解和其他增强注解,如@Before @After @AfterReturning @AfterThrowing @Around  --><context:component-scan base-package="com.pojo,com.aspect"><context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"></context:include-filter></context:component-scan>
</beans>

4.2.5 启动类Test

package com.test;import com.pojo.Hello;
import com.pojo.World;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {public static void main(String[] args) {//加载配置文件 applicationContext.xmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });//hello类Hello hello=(Hello)context.getBean("hello");hello.foo();hello.addUser("小明","1000");try{hello._functionException(5);}catch (Exception e){}//world类World world=(World) context.getBean("world");world.bar();}
}

4.2.6 运行结果

这里是Around增强
Around增强:执行目标方法之前,模拟开始事务...
这里是Before增强
Before增强:被织入增强处理的目标方法为: foo
Before增强:目标方法的参数为: []
Before增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe
执行hello组件的foo()方法
Around增强:执行目标方法之后,模拟结束事务...
这里是AfterReturning增强,打印目标方法返回值: null
AfterReturning增强:被织入增强处理的目标方法为: foo
AfterReturning增强:目标方法的参数为: []
AfterReturning增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe
这里是After增强
After增强:被织入增强处理的目标方法为: foo
After增强:目标方法的参数为: []
After增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe这里是Around增强
Around增强:执行目标方法之前,模拟开始事务...
这里是Before增强
Before增强:被织入增强处理的目标方法为: addUser
Before增强:目标方法的参数为: [[增加的前缀]小明, 1000]
Before增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe
执行Hello组件的addUser添加用户:[增加的前缀]小明
Around增强:执行目标方法之后,模拟结束事务...
这里是AfterReturning增强,打印目标方法返回值: null
AfterReturning增强:被织入增强处理的目标方法为: addUser
AfterReturning增强:目标方法的参数为: [[增加的前缀]小明, 1000]
AfterReturning增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe
这里是After增强
After增强:被织入增强处理的目标方法为: addUser
After增强:目标方法的参数为: [[增加的前缀]小明, 1000]
After增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe这里是Around增强
Around增强:执行目标方法之前,模拟开始事务...
这里是Before增强
Before增强:被织入增强处理的目标方法为: _functionException
Before增强:目标方法的参数为: [5]
Before增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe
这里是AfterThrowing增强处理,打印目标方法中抛出的异常: java.lang.ArithmeticException: / by zero
这里是After增强
After增强:被织入增强处理的目标方法为: _functionException
After增强:目标方法的参数为: [5]
After增强:被织入增强处理的目标对象为: com.pojo.Hello@1d2adfbe这里是Around增强
Around增强:执行目标方法之前,模拟开始事务...
这里是Before增强
Before增强:被织入增强处理的目标方法为: bar
Before增强:目标方法的参数为: []
Before增强:被织入增强处理的目标对象为: com.pojo.World@36902638
执行World组件的bar()方法
Around增强:执行目标方法之后,模拟结束事务...
这里是AfterReturning增强,打印目标方法返回值: null
AfterReturning增强:被织入增强处理的目标方法为: bar
AfterReturning增强:目标方法的参数为: []
AfterReturning增强:被织入增强处理的目标对象为: com.pojo.World@36902638
这里是After增强
After增强:被织入增强处理的目标方法为: bar
After增强:目标方法的参数为: []
After增强:被织入增强处理的目标对象为: com.pojo.World@36902638

解释:输出结果分为四段,分别是
hello.foo();
hello.addUser(“小明”,“1000”);
hello._functionException(5);
world.bar();
给出解释,为节约篇幅,仅解释 hello.addUser(“小明”,“1000”);和hello._functionException(5);两个就好了,一个带两个参数,一个带异常,hello.foo();和world.bar(); 都是一样的,解释如下图:

4.3 Spring AOP实践:XML配置文件方式实现

4.3.1 目录结构

4.3.2 两个POJO类

package com.pojo;public class Hello {public void foo() {System.out.println("执行hello组件的foo()方法");}public void addUser(String name, String pass) {System.out.println("执行Hello组件的addUser添加用户:" + name);}public void _functionException(int orgin) {int a = orgin / 0;}
}
package com.pojo;public class World {public void bar() {System.out.println("执行World组件的bar()方法");}
}

4.3.3 三个Aspect类

package com.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;import java.util.Arrays;
//该类中有四个通知 @Before @AfterReturning @After @Around  所以称为FourAdviceTest
public class FourAdviceTest {public Object aroundFunction(ProceedingJoinPoint joinPoint) throws java.lang.Throwable{System.out.println();System.out.println("Around增强:执行目标方法之前,模拟开始事务...");Object[] args = joinPoint.getArgs();if (args != null && args.length > 0 && args[0].getClass()==String.class) {args[0] = "[增加的前缀]" + args[0];}Object rvt = joinPoint.proceed(args);System.out.println("Around增强:执行目标方法之后,模拟结束事务...");if (rvt != null && rvt instanceof Integer)rvt = (Integer) rvt * (Integer) rvt;return rvt;}public void beforeFunction(JoinPoint joinPoint){System.out.println("FourAdviceTest-Before增强:模拟执行权限检查");System.out.println("FourAdviceTest-Before增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("FourAdviceTest-Before增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("FourAdviceTest-Before增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}public void afterReturningFunction(JoinPoint joinPoint, Object rvt){System.out.println("AfterReturning增强:获取目标方法的返回值: "+rvt);System.out.println("AfterReturning增强:模拟记录日志功能...");System.out.println("AfterReturning增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("AfterReturning增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("AfterReturning增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}public void afterFunction(JoinPoint joinPoint){System.out.println("After增强:模拟方法结束后的释放资源...");System.out.println("After增强:被织入增强处理的目标方法为: "+joinPoint.getSignature().getName());System.out.println("After增强:目标方法的参数为: "+ Arrays.toString(joinPoint.getArgs()));System.out.println("After增强:被织入增强处理的目标对象为: "+joinPoint.getTarget());}
}
package com.aspect;public class RepairAspect {public void doRecoveryActions(Throwable ex){System.out.println("打印异常:"+ex);}
}
package com.aspect;//该类中有一个通知 @Before  因为这是第二个@Before  所以称为SecondAdviceTest
public class SecondAdviceTest {public void authority(String aa){System.out.println("SecondAdviceTest-Before增强:模拟执行检查"+"目标方法的参数为: "+aa);}
}

4.3.4 Spring配置文件appliationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd"><aop:config><aop:pointcut id="myPointcut" expression="execution(* com.pojo.*.*(..))"></aop:pointcut><aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"><aop:after pointcut="execution(* com.pojo.*.*(..))" method="afterFunction"></aop:after><aop:before pointcut="execution(* com.pojo.*.*(..))" method="beforeFunction"></aop:before><aop:after-returning pointcut="execution(* com.pojo.*.*(..))" method="afterReturningFunction"returning="rvt"></aop:after-returning><aop:around pointcut="execution(* com.pojo.*.*(..))" method="aroundFunction"></aop:around></aop:aspect><aop:aspect id="secondAdviceAspect" ref="secondAdviceBean" order="1"><aop:before pointcut="execution(* com.pojo.*.*(..)) and args(aa)" method="authority"></aop:before></aop:aspect><aop:aspect id="afterThrowingAdviceAspect" ref="afterThrowingAdviceBean"><aop:after-throwing pointcut-ref="myPointcut" method="doRecoveryActions" throwing="ex"></aop:after-throwing></aop:aspect></aop:config><bean id="fourAdviceBean" class="com.aspect.FourAdviceTest"></bean><bean id="secondAdviceBean" class="com.aspect.SecondAdviceTest"></bean><bean id="afterThrowingAdviceBean" class="com.aspect.RepairAspect"></bean><bean id="hello" class="com.pojo.Hello"></bean><bean id="world" class="com.pojo.World"></bean>
</beans>

4.3.5 Test启动类

package com.test;import com.pojo.Hello;
import com.pojo.World;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {public static void main(String[] args) {//加载配置文件 applicationContext.xmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});//hello类Hello hello = (Hello) context.getBean("hello");hello.foo();hello.addUser("小明", "1000");try {hello._functionException(5);} catch (Exception e) {}//world类World world = (World) context.getBean("world");world.bar();}
}

4.3.6 运行结果

和使用注解方式基本一样(也就是打印语句的说法有少许不同),这里略过。

五、小结

本文分为三个部分,分别介绍AOP基础知识,以AspectJ AOP为例介绍静态AOP,以Spring AOP为例介绍动态AOP,其中以Spring AOP为重点,全文从AOP到AspectJ AOP,再到Spring AOP,希望对Java学习者有用。
天天打码,天天进步!

AspectJ工程代码:
https://download.csdn.net/download/qq_36963950/12182608

Spring AOP工程代码(注解方式):https://download.csdn.net/download/qq_36963950/12182612

Spring AOP工程代码(XML配置方式):https://download.csdn.net/download/qq_36963950/12182620

从AOP到Spring AOP相关推荐

  1. AOP和Spring AOP介绍

    AOP和Spring AOP介绍 文章目录 AOP和Spring AOP介绍 一.AOP简介 二. 传统开发存在的弊端 三. AOP实现原理 四.Spring AOP 五.AOP相关术语 一.AOP简 ...

  2. aopaspect区别_面试官:什么是AOP?Spring AOP和AspectJ的区别是什么?

    AOP(Aspect Orient Programming),它是面向对象编程的一种补充,主要应用于处理一些具有横切性质的系统级服务,如日志收集.事务管理.安全检查.缓存.对象池管理等. AOP实现的 ...

  3. android aop静态方法,spring aop 不能对静态方法进行增强解决

    想要通过aop的方式记录HttpUtils发出的post请求日志,但是 aop 不能对静态方法进行增强.只能对实例方法进行增强.. 如果一定要增强静态方法,我们可以对目标类使用单例模式,然后通过调用实 ...

  4. Spring AOP Capability and goals

    5.1.AOP概念 让我们首先定义一些中心AOP概念和术语.这些术语不是特定于Spring的.不幸的是,AOP术语不是特别直观.但是,如果Spring使用自己的术语,那将更加令人困惑. 方面:跨越多个 ...

  5. 9000+ 字,彻底征服 Spring AOP ,美滋滋

    基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, ...

  6. Spring 学习笔记(二)Spring AOP

    前言 容器和AOP是Spring的两大核心.本文将来学习Spring AOP. AOP是什么? AOP在计算机科学领域还是相对年轻的概念,由Xerox PARC公司发明.Gregor Kiczales ...

  7. Spring AOP知识点简介

    文章目录 1.什么是AOP 1.1.AOP术语 1.2.AOP框架 2.动态代理 2.1.JDK动态代理 2.2.CGLIB动态代理 3.基于代理类的AOP实现 3.1.Spring的通知类型 3.2 ...

  8. 带你理解Spring AOP

    AOP概述 在我们的日常开发中,除了正常业务逻辑外,还可能经常会需要在业务逻辑的特定位置加入日志,以便于调试和问题分析.但是这种插入日志的逻辑和业务逻辑间并不存在连续性和依赖性,这种逻辑侵入随着项目的 ...

  9. Spring AOP 功能使用详解

    前言 AOP 既熟悉又陌生,了解过 Spring 人的都知道 AOP 的概念,即面向切面编程,可以用来管理一些和主业务无关的周边业务,如日志记录,事务管理等:陌生是因为在工作中基本没有使用过,AOP ...

最新文章

  1. 项目总结---- imageLoder 的2个Bug解决方法、1.9.4如何选择性删除disk缓存和其它一些错误。...
  2. 微信开发提示未绑定网页开发者
  3. 231 Power of Two 2的幂
  4. CLR Essential Types
  5. android 关闭软键盘_HTC官方社区明天正式关闭,收入持续下滑或是直接原因
  6. java左手画圆右手画方_左手画圆,右手画方作文
  7. 皮肤的实时3S渲染(OpenGL + GLSL)
  8. kotlin 查找id_Kotlin程序查找Square区域
  9. 登上热搜!这可能是中国最穷的211大学
  10. php开发中常用函数总结,PHP开发中常用函数总结
  11. 是驴是骡,遛一遛就知道了
  12. blackfriday markdown的自动换行 go lang 正则替换字符串时遇到的坑,转义解析其中的 $1 $name 等
  13. markdown 书写代码
  14. Spark SVN + Eclipse 3.3 + Subversive Installation Guide
  15. IT运维服务体系建设思路
  16. 软件工程项目经理必备能力
  17. 【蓝桥杯省赛真题34】Scratch九宫格 少儿编程scratch蓝桥杯省赛真题讲解
  18. python安装.egg文件_芳草地-小狍子的空间_百度空间
  19. CSDN积极响应网信办“知识社区问答”行为规范管理,共筑健康网络空间
  20. 关于线上支付的实现思想方法与例子

热门文章

  1. 简易员工信息管理系统
  2. 微信小程序开发初学:图片组件 - image
  3. 【历史上的今天】8 月 8 日:中国第一个校园 BBS 成立;网景通信上市;EarthLink 创始人出生
  4. .NET Core基于Furion框架实现依赖注入
  5. 压缩感知(compressed sensing)的通俗解释
  6. 社区服务开启“云”智慧社区时代,CDN高防能否成为服务器的源动力呢?
  7. 【Python--torch(激活函数说明+代码讲解)】激活函数(sigmoid/softmax/ELU/ReLU/LeakyReLU/Tanh)
  8. granger Z-score问题
  9. mysql workbench 主从_MySQL Workbench 使用教程 (四)
  10. js input 正则保留2位小数中文拼音输入问题 + 限制输入整数的方案