Spring AOP原理详解及实例

  • 1.Spring AOP简介
  • 2.AOP与OOP对比
  • 3.AOP使用场景
  • 4.AOP相关概念
  • 5.AOP实例
    • 5.1 基于xml配置方式
    • 5.2 基于注解配置方式
    • 5.3 @AspectJ切点函数
  • 6.可能出现的问题及解决方法
    • 6.1 java.lang.IllegalArgumentException: error at :: 0 can't find referenced pointcut……

观前提示:

本文所使用的Eclipse版本为Photon Release (4.8.0),IDEA版本为ultimate 2019.1,JDK版本为1.8.0_141,Tomcat版本为9.0.12。

1.Spring AOP简介

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.AOP与OOP对比

AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

上面的陈述可能过于理论化,举个简单的例子,对于“雇员”这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。

同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。

换而言之,OOD/OOP面向名词领域,AOP面向动词领域。

3.AOP使用场景

AOP用来封装横切关注点,具体可以在下面的场景中使用:

  1. Authentication 权限

  2. Caching 缓存

  3. Context passing 内容传递

  4. Error handling 错误处理

  5. Lazy loading 懒加载

  6. Debugging 调试

  7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准

  8. Performance optimization 性能优化

  9. Persistence 持久化

  10. Resource pooling 资源池

  11. Synchronization 同步

  12. Transactions 事务

4.AOP相关概念

  1. 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。

  2. 连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。

  3. 通知/增强(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。spring aop advice的类型:
    1、前置通知(before advice),在目标方法执行之前执行。
    2、返回后通知(after returning advice),在方法正常执行结束之后的通知,可以访问到方法的返回值。
    3、抛出异常后通知(after throwing advice),在目标方法出现异常时执行的代码,可以访问到异常对象,且可以指定出现特定异常执行此方法。
    4、后置通知:(after[finally] advice),在目标方法执行之后执行(无论是否发生异常)。
    5、环绕通知:(around advice),可以实现上述所有功能。

  4. 切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上

  5. 引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口

  6. 目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO

  7. AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

  8. 织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

5.AOP实例

需要的jar包:Jar包链接详情点我

需要的jar包
aspectjrt-1.9.2.jar、aspectjweaver-1.9.2.jar

5.1 基于xml配置方式

这里我使用的是Eclipse

目录结构

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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"><bean id="userService" class="cn.com.demo.service.UserService"/><bean id="logAopDemo" class="cn.com.demo.aop.LogAop"/><!-- 面向切面编程 --><aop:config><aop:aspect ref="logAopDemo"><!-- 定义切点 --><aop:pointcut expression="execution(* *..*(..))" id="pointCut"/><!-- 声明前置通知 (在切点方法被执行前调用)--><aop:before method="beforeAdvice" pointcut-ref="pointCut"/><!-- 声明后置通知 (在切点方法被执行后调用)--><aop:after method="afterAdvice" pointcut-ref="pointCut"/></aop:aspect></aop:config>
</beans>

注:aop:aspect 子节点还可配置

<aop:config><aop:aspect ref="logAopDemo"><!-- 定义切点 --><aop:pointcut expression="execution(* *..*(..))" id="pointCut"/><!-- 声明前置通知 (在切点方法被执行前调用)--><aop:before method="beforeAdvice" pointcut-ref="pointCut"/><!-- 声明后置通知 (在切点方法被执行后调用)--><aop:after method="afterAdvice" pointcut-ref="pointCut"/><aop:after-returning method="aferReturning" pointcut-ref="pointCut"/><aop:after-throwing method="aferThrowing" pointcut-ref="pointCut"/><aop:around method="around" pointcut-ref="pointCut"/></aop:aspect></aop:config>

日志类LogAop.java

package cn.com.demo.aop;public class LogAop {public void beforeAdvice() {System.out.println("beforeAdvice");}public void afterAdvice() {System.out.println("afterAdvice");}
}

UserService.java

package cn.com.demo.service;public class UserService {public void insertUser() {System.out.println("插入用户成功");}public boolean updateUser() {System.out.println("更新用户成功");return true;}
}

测试类TestAop

package cn.com.demo.test;import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.com.demo.service.UserService;public class TestAop {private ClassPathXmlApplicationContext ac;@Beforepublic void before() {ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");}@Testpublic void test() {try {UserService userService = (UserService) ac.getBean("userService");userService.insertUser();userService.updateUser();} catch (Exception e) {e.printStackTrace();}}
}

测试结果

5.2 基于注解配置方式

这里我使用的是Eclipse

目录结构

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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"><bean id="userService" class="cn.com.demo.service.UserService"/><!-- 启用注释驱动自动注入 --><!-- <context:annotation-config/> --><!-- 配置自动扫描的包 --><context:component-scan base-package="cn.com.demo"></context:component-scan><!-- 开启aop注解方式,此步骤不能少,这样java类中的aop注解才会生效 --><aop:aspectj-autoproxy/>
</beans>

<aop:aspectj-autoproxy/>为开启aop注解方式,此步骤必不能少,这样java类中的aop注解才会生效。
日志类LogAop.java

package cn.com.demo.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Component
@Aspect
public class LogAop {@Pointcut("execution(* cn.com.demo.service.UserService.insertUser(..))")public void ponitCut() {}@Before("ponitCut()")public void beforeAdvice() {System.out.println("beforeAdvice");}@After("ponitCut()")public void afterAdvice() {System.out.println("afterAdvice");}//环绕通知。注意要有ProceedingJoinPoint参数传入@Around("ponitCut()")public void around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("注解类型环绕通知..环绕前");pjp.proceed();//执行方法System.out.println("注解类型环绕通知..环绕后");}
}

UserService.java

package cn.com.demo.service;public class UserService {public void insertUser() {System.out.println("插入用户成功");}public boolean updateUser() {System.out.println("更新用户成功");return true;}
}

测试类TestAop

package cn.com.demo.test;import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.com.demo.service.UserService;public class TestAop {private ClassPathXmlApplicationContext ac;@Beforepublic void before() {ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");}@Testpublic void test() {try {UserService userService = (UserService) ac.getBean("userService");userService.insertUser();} catch (Exception e) {e.printStackTrace();}}
}

运行结果

5.3 @AspectJ切点函数

参考文章:@AspectJ切点函数详解

6.可能出现的问题及解决方法

6.1 java.lang.IllegalArgumentException: error at :: 0 can’t find referenced pointcut……

如果出现如下错误:

可能是你的aspectjweaver和aspectjrt与你的jdk版本不匹配。

Spring AOP原理详解及实例相关推荐

  1. Spring事务原理详解

    一.使用 spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾. 1.配置数据源 spring.datas ...

  2. Spring之AOP原理详解

    概念 AOP 实现原理 AOP 动态代理的实现原理 实现AOP 链接上一篇:spring框架组件分析 概念 AOP spring用代理类包裹切面,把他们织入到Spring管理的bean中.也就是说代理 ...

  3. Spring Boot原理详解(一)

    概念: Spring Boot是由Pivotal团队提供的全新框架,属于spring旗下的一个项目,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,它使 ...

  4. Spring AOP原理浅析及入门实例

    上篇问题及Spring AOP实现原理浅析 上篇说了一个AOP编程问题,那是一个错误的AOP案例.它的错误在A类中,再次粘贴A类代码: @Componentpublic class AImpl imp ...

  5. Spring AOP知识详解

    本文来详细说下spring中的aop内容 文章目录 Spring AOP概述 Spring AOP一代 Pointcut Jointpoint Advice Advisor 织入 Spring AOP ...

  6. Spring工作原理详解

    2019独角兽企业重金招聘Python工程师标准>>> Spring原理 最核心的就是IOC,动态注入DI,利用java里的反射,让一个对象的创建不用new了,可以自动的生产.Spr ...

  7. Spring AOP代理详解

    最近在看Spring这块,对AOP的代理有些疑惑,特整理如下. 1.*Java为什么要引入AOP代理的概念?* AOP(面向切面编程)通常,系统由很多组件组成,每个组件负责一部分功能,然而,这些组件也 ...

  8. Spring AOP 切点详解

    本文内容 Spring 10种切点表达式详解 切点的组合使用 公共切点的定义 声明切点@Poincut @Poincut 的使用格式如下: @Poincut("PCD") // 切 ...

  9. Spring AOP全面详解(超级详细)

    如果说IOC 是 Spring 的核心,那么面向切面编程AOP就是 Spring 另外一个最为重要的核心@mikechen AOP的定义 AOP (Aspect Orient Programming) ...

  10. spring注解:spring aop注解详解

    一. AOP的基本概念 Aspect(切面):通常是一个类,里面可以定义切入点和通知 Pointcut(切点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式 JointPoint(连接点) ...

最新文章

  1. Codeforces Round #276 (Div. 2)
  2. 只需2小时,成本不到7块,你我皆可制作的3D机器人
  3. 大数据文字游戏_基于大数据的游戏化教学系统研究.docx
  4. 浅析CSS——元素重叠及position定位的z-index顺序
  5. Css标题中图片居中,图片居中:任意图片在div里的上下垂直都居中!
  6. 形容等待时间长的句子_雅思听力该如何准确辨别句子结构?学会结构精听,雅思8分轻松get!...
  7. C++编程思想:继承与虚函数以及多态
  8. PHP网站如何解决大流量与高并发的问题
  9. 粘性定位(HTML、CSS)
  10. 【口令破解】远程口令破解和本地口令破解(crunch 字典工具和hydra工具)
  11. java showtype_GitHub - kedarui/showapi_sdk_java: showapi_sdk_java
  12. 用户价值分层——基于RFM模型的研究分析
  13. 基于C++和opengl实现太阳系动画演示系统 课程论文+项目源码
  14. 计算机usb接口无法充电,电脑可充电USB接口不能使用怎么办
  15. Centos7.4-docker安装部署实战
  16. GLSL 参考GIMP源码实现色彩平衡调节
  17. BELLHOP 关于Actup冲激响应的绘制
  18. 后端做app连续会员包月功能 -- IOS连续订阅 支付宝周期扣款
  19. 帝国CMS对接百度智能小程序的方法
  20. 老男孩mysql运维dba实战21部完整版_老男孩MySQL DBA 运维课程全套,资源教程下载...

热门文章

  1. dstwo linux 模拟器,dstwo使用gba模拟器V1.30版本下载和使用作弊功能的作弊教程
  2. 软考系统集成项目管理工程师真题
  3. kX3552 驱动、安装、插件集合贴
  4. 循序渐进!疯狂java讲义第五版pdf蓝奏云下载
  5. fluidsim元件库下载_FluidSIM下载
  6. 宿命传说2之女神召唤java_开局:召唤金色暗影
  7. pyecharts世界地图map,geo可视化优化调整
  8. 2022-2027年中国虾养殖行业市场调研及未来发展趋势预测报告
  9. 监督计算机控制系统的应用,计算机智能控制系统的应用类型
  10. Android手势密码解锁设计