问题:什么是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的使用相关推荐

  1. spring中aop事务

    文章目录 事务 为什要用到Spring中AOP事务 事物的特性 ACID 事务并发问题 事务的隔离级别 spring事务管理 事务操作 事务操作对象 spring管理事务的属性介绍 spring管理事 ...

  2. Spring中AOP源码剖析

    Spring中AOP源码剖析 关键词 aop的增强发生在后置处理器中(没有循环依赖) 最终增强是通过 递归调用 ,层层增强 一.环境准备 1.1 bean和接口 public class AopBea ...

  3. spring中AOP(面向切面编程)

    spring中AOP(面向切面编程) 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容 ...

  4. 动态代理以及对应Spring中AOP源码分析

    AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...

  5. Spring中AOP相关的API及源码解析,原来AOP是这样子的

    前言 之所以写这么一篇文章主要是因为下篇文章将结束Spring启动整个流程的分析,从解析配置到创建对象再到属性注入最后再将创建好的对象初始化成为一个真正意义上的Bean.因为下篇文章会涉及到AOP,所 ...

  6. spring中AOP动态代理的两种方式

    AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...

  7. Spring中AOP开发步骤

    AOP:不是由Spring定义.AOP联盟的组织定义.Spring中的通知:(增强代码)前置通知 org.springframework.aop.MethodBeforeAdvice* 在目标方法执行 ...

  8. spring中aop默认使用jdk动态代理,springboot2以后默认使用cglib来实现动态代理详解

    Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...

  9. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

最新文章

  1. dedephp geteditor(,cms教程:dedecms修改后台编辑器参数GetEditor的方法
  2. 大疆aeb连拍_前后双屏幕:大疆OSMO Action行动相机规格与谍照曝光
  3. PHP 入门 - 8.数据库
  4. 工厂设计模式–一种有效的方法
  5. CALayer 4 详解 -----转自李明杰
  6. gzdeflate函数_PHP中的gzcompress、gzdeflate、gzencode函数详解
  7. 国际市场营销知识框架图_货币银行学知识怎么学?知识点很杂乱?已经为你整理好了!...
  8. 《剑指offer》青蛙跳台阶
  9. confluence统计_【漏洞预警】confluence远程代码执行漏洞(CVE-2019-3396)
  10. iOS开发图片合成,多张图片合成一张图片
  11. 不再当码农-Flash AS3.0多个影片剪辑实现同一功能循环问题
  12. 最实用的计算机系统清理加速,最实用的win7电脑清理垃圾方法分享
  13. Linux网络管理18:DHCP服务器
  14. 12306脱库疑云:410万用户数据仅售20美元!
  15. 思科http服务器显示设置,思科里面的服务器怎么设置
  16. OpenCL: 从零开始学习OpenCL开发
  17. 手机sim卡插到电脑上网_淘汰的手机别扔掉,这样设置变身4G上网卡
  18. 国内有哪些好用的 Online Judge
  19. 网卡清空缓存命令_怎么清除dns缓存 查看与刷新本地DNS缓存方法 (全文)
  20. 3和4之间纯在无理数吗

热门文章

  1. java applet程序设计,Java Applet程序设计基础
  2. bootstraptable 列隐藏_bootstrap中table如何隐藏列?
  3. HTML+CSS+JS实现 ❤️酷炫彩虹旋转隧道特效❤️
  4. 470p 更换固态硬盘_联想G510换固态硬盘遇到的问题
  5. java 解压到内存,Java GZip 基于内存实现压缩和解压的方法
  6. 微信 语音转文字 java,在微信——怎么将语音转化为文字,你需要学习了
  7. Java 集合中存在多种数据类型
  8. Spring Boot MyBatis
  9. android jackson 解析json字符串,android:json解析的两个工具:Gson和Jackson的使用小样例...
  10. 更换计算机桌面背景的教案,桂科版三年级下册任务一 美化桌面背景免费教学设计...