Spring中AOP的使用
问题:什么是AOP?
答:AOP基本概念:Aspect-Oriented Programming,面向方面编程的简称,Aspect是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern), 从关注点中分离出横切关注点是面向方面程序设计的核心所在。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特 定领域问题代码的调用,业务逻辑同特定领域问题的关系通过方面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
个人理解:所谓的AOP就是把我们的程序的执行看成是一个方块的面包,然后切成了一片一片的吐司--这些吐司就是我们一个一个的方法。然后在这些吐司片的前面,后面、甚至是里面来做一些特定条件下发生的特定事情,比如嵌入几个葡萄干、给前面加苹果酱、给后面加草莓酱这样的事情。。优势在于你可以在自己的AOP方法中规定一个加苹果酱的理由,满足这个理由的话就可以加苹果酱,而不用在每个方法中都特定的指出加苹果酱,加草莓酱什么的··个人理解···。
AOP的实现有很多的方式,我这边使用Spring中自带的aop来做一些业务逻辑的实现。
在Spring中实现aop的方式有两种,分别是通过xml配置和通过注解配置。下面来介绍这两种方式。
在介绍他们之前先看一下项目的结构:
上图中ServiceAspect是我们使用注解的方式来实现AOP的类,InteceptorXML是使用XML来实现AOP的类;TestAop是测试方法;TestServiceImpl;TestService是用来被AOP的动作;(需要明确的是,AOP的动作建议都发生在service层面。)application-context.xml是我的配置文件。
1.通过注解配置。
我注解AOP的代码如下:
package test.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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;import test.entity.User;@Component
// 声明这是一个组件
@Aspect
// 声明这是一个切面bean
public class ServiceAspect {// 配置切入点,该方法无方法体,主要是为了同类中其他方法使用此处配置的切入点 ----见(1)@Pointcut("execution(* test.service..*.*(..))")public void aspect() {}// 配置前置通知,使用在方法aspect()上注册的切入点,同时接受JoinPoint切入点对象,可以没有该参数 ----见(2)@Before("aspect()&&args(id)")public void before(JoinPoint joinPoint, long id) {System.out.println(id + "------------------");System.out.println("before-->" + joinPoint);}// 配置后置通知,使用在方法aspect()上注册的切入点----见(3)@After("aspect()&&args(id)")public void after(JoinPoint joinPoint, long id) {System.out.println(id + "after----------------------");System.out.println("after-->" + joinPoint);}// 配置环绕通知----见(4)@Around("aspect()")public Object around(JoinPoint joinPoint) {long start = System.currentTimeMillis();try {Object o=((ProceedingJoinPoint) joinPoint).proceed();User user = (User)o;System.out.println("-----around======="+user.toString());long end = System.currentTimeMillis();System.out.println("around -->" + joinPoint + "\tUse time : "+ (end - start) + " ms!");return user;} catch (Throwable e) {long end = System.currentTimeMillis();System.out.println("around __>" + joinPoint + "\tUse time : "+ (end - start) + " ms with exception : " + e.getMessage());return null;}}// 配置后置返回通知,使用在方法aspect()上注册的切入点----见(5)@AfterReturning(pointcut = "aspect()", returning = "returnVal")public void afterReturning(JoinPoint joinPoint, Object returnVal) {System.out.println("afterReturning executed, return result is "+ returnVal);}// 配置抛出异常后通知,使用在方法aspect()上注册的切入点----见(6)@AfterThrowing(pointcut = "aspect()", throwing = "ex")public void afterThrow(JoinPoint joinPoint, Exception ex) {System.out.println("afterThrow--> " + joinPoint + "\t"+ ex.getMessage());}
}
很多内容在注释中已经有了,这里说一下几个关键的容易让人不明白的地方;
(1)@Pointcut("execution(* test.service..*.*(..))")就是我们定义的切入点,在括号里面的参数是指定了哪些方法是在考虑切入的范围内的;
* test.service..*.*(..)可以这样来解剖:
第一个* :表示被拦截的方法可以是任意的返回类型;
test.service:指定了要拦截的包;
..:这两个..表示的是被指定的拦截包test.service中所有的子包中的类的方法都要考虑到拦截的范围中;
*:表示任意的类;
.*:表示任意的方法;
(..):表示任意的方法参数;
总结起来,就是告诉我们这样一个信息:要拦截test.service中所有子包中的所有类的所有方法,这些方法的返回值可以是任意的,参数可以是任意的。
当然,我们也可以特定许多内容,但是格式不要变;例如:
@Pointcut(“execution(* test.service..*.add*(..))”)
那么所要拦截的方法就必须以add来开头了。
切入点的方法中不实现任何的操作,作用只是提供给其他的切面来使用。
(2)
@Before("aspect()&&args(id)")中的 aspect(),指定指定切入点的方法,就是我们定义为pointCut的aspect()方法,然后args(id),我们获取了所拦截的方法的传入的参数中的id;在before方法中我们可以在切入点执行以前来做一些操作。 其中的joinPoint是切入点的相关信息。
(3)
@After("aspect()&&args(id)")同(2),只是这是在切入点执行完成以后来做出一些处理。
(4)
@Around("aspect()")是环绕通知,在环绕通知中我们能切入点的很多内容进行修改;
其中通过Object o=((ProceedingJoinPoint) joinPoint).proceed();我们就可以让切入点的方法完成,获得他的运行结果;
然后User user = (User)o;我们把它转换为User对象,如果在return user,之前我们加上user.setName("after aa");就可以改变切入点的运行结果。
这种操作对于很多的错误检测以及格式检测是很有用处的。
(5)
@AfterReturning(pointcut = "aspect()", returning = "returnVal")
这里是切入点有返回结果后做的操作,通过returning的定义我们能获得切入点的返回结果;
(6)
@AfterThrowing(pointcut = "aspect()", throwing = "ex")
这里可以在切入点抛出异常后做一些工作,通过定义throwing我们能获得抛出的异常对象。
相关代码:
application-context.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:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="test"> <!--开启spring自定义的包扫描,我定义的为扫描test包下所有内容-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--这里不扫描controller,在mvc中扫描,安全又可靠-->
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><!--开启注释方式的spring aop-->
<bean id="userService" class="test.service.impl.UserService"></bean><!--注入userService-->
</beans>
UserService
package test.service.impl;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;import test.entity.User;public class UserService {private final static Log log = LogFactory.getLog(UserService.class);public User get(long id) {if (log.isInfoEnabled()) {log.info("getUser method . . .");}User user = new User(1, "test");return user;}public void save(User user) {if (log.isInfoEnabled()) {log.info("saveUser method . . .");}}public boolean delete(long id) throws Exception {if (log.isInfoEnabled()) {log.info("delete method . . .");throw new Exception("spring aop ThrowAdvice演示");}return false;}
}
test方法
package demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import test.entity.User;
import test.service.impl.UserService;public class TestAop {public static void main(String[] args) {ApplicationContext aContext = new ClassPathXmlApplicationContext("application-context.xml");//加载spring文件UserService userService = (UserService) aContext.getBean("userService");//获得userserviceUser user =userService.get(1L);//调用get方法;System.out.println(user);try {userService.delete(1L);//调用delete方法;} catch (Exception e) {System.out.println("Delete user : " + e.getMessage());}}
}
测试结果:
2.通过XML来配置
通过xml来配置AOP,操作都在xml文件中完成
在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:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- <context:component-scan base-package="test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
<bean id="userService" class="test.service.impl.UserService"></bean><bean id="inteceptorXML" class="test.aop.InteceptorXML"></bean>
<aop:config>
<aop:aspect id="aspectd" ref="inteceptorXML">
<aop:pointcut expression="execution(* test.service..*.*(..))" id="mypointCutMethod"/>
<aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />
</aop:aspect>
</aop:config>
</beans>
在xml中我们指定了用来作为拦截器的bean----inteceptorXML,类似的指定了切入点
<aop:aspect id="aspectd" ref="inteceptorXML">指定了拦截器为interceptorXML。
execution(* test.service..*.*(..)),并指定了id为mypointCutMethod,然后定义了
<aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />
指定了调用doAccessCheck来做before拦截,其他拦截我没有指定,这里都可以指定的。
inteceptorXml
package test.aop;import org.aspectj.lang.ProceedingJoinPoint;public class InteceptorXML {public void doAccessCheck() {System.out.println("before advice");}public void doWriteLog() {System.out.println("after advice");}public void doWriteErrorLog() {System.out.println("Exception advice");}public Object doAroundMethod(ProceedingJoinPoint pjp) throws Throwable {System.out.println("enter around advice method.");Object obj = pjp.proceed();System.out.println("exit around advice method.");return obj;}
}
运行上面的测试方法,得到的结果如下:
Spring中AOP的使用相关推荐
- spring中aop事务
文章目录 事务 为什要用到Spring中AOP事务 事物的特性 ACID 事务并发问题 事务的隔离级别 spring事务管理 事务操作 事务操作对象 spring管理事务的属性介绍 spring管理事 ...
- Spring中AOP源码剖析
Spring中AOP源码剖析 关键词 aop的增强发生在后置处理器中(没有循环依赖) 最终增强是通过 递归调用 ,层层增强 一.环境准备 1.1 bean和接口 public class AopBea ...
- spring中AOP(面向切面编程)
spring中AOP(面向切面编程) 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容 ...
- 动态代理以及对应Spring中AOP源码分析
AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...
- Spring中AOP相关的API及源码解析,原来AOP是这样子的
前言 之所以写这么一篇文章主要是因为下篇文章将结束Spring启动整个流程的分析,从解析配置到创建对象再到属性注入最后再将创建好的对象初始化成为一个真正意义上的Bean.因为下篇文章会涉及到AOP,所 ...
- spring中AOP动态代理的两种方式
AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...
- Spring中AOP开发步骤
AOP:不是由Spring定义.AOP联盟的组织定义.Spring中的通知:(增强代码)前置通知 org.springframework.aop.MethodBeforeAdvice* 在目标方法执行 ...
- spring中aop默认使用jdk动态代理,springboot2以后默认使用cglib来实现动态代理详解
Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...
- Spring中AOP实现
1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...
最新文章
- 新功能:阿里云负载均衡SLB支持HTTPS虚拟主机功能(SNI)
- 【BZOJ】4873: [Shoi2017]寿司餐厅
- UIKIT网页基本结构学习
- Spring Boot 返回 JSON 数据,一分钟搞定!
- [No00009D]使用visual studio 2015 update3打包程序安装包的简单方法(不需要InstallShield)...
- [css] CSS content属性特殊字符有哪些?
- excel线性拟合的斜率_协方差分析:方差分析与线性回归的统一
- 【leecode】小练习(简单8题)
- 案例33-用户退出功能
- 148. php in_array()
- 使用python爬取链家上海二手房信息的案例
- matlab插值与拟合例题_数学建模matlab插值与拟合
- 山东理工大学SDUT - ACM OJ 题: Python代码 及分析
- 批量Word转换成PDF,用这方法超简单
- QQ群反向昵称、恶搞昵称的原理
- liunx检测上下行带宽及丢包率
- 2021年 985 网络空间安全专业 保研路
- 使用 U 盘启动盘安装 Windows 7 旗舰版系统
- ZBlog源码资源站整站打包-带天兴娱乐资源主题+墨初用户中心插件
- C语言实验设备预约管理系统
热门文章
- 震惊! Leftmost Digit
- python dict hash_【python-dict】dict的使用及实现原理
- python 堆_面试再问你什么是堆和栈,你就把这篇文章甩给他
- 深入jvm虚拟机第三版源码_深入JVM虚拟机,阿里架构师直言,这份文档真的是JVM最深解读...
- php预处理获取改变行数,php – 使用MySQLi预处理语句时无法获取行数...
- C语言字符串倒排,C语言兑现简单的倒排文件索引
- HTML+CSS+JS实现love520爱心表白
- php如何生成本地文档,php如何生成word文件
- python基础课程5(看代码看注释)--numpy
- 零窗口探测怎么抓包_Linux服务器下的HTTP抓包分析