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;}
}


运行上面的测试方法,得到的结果如下:




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis generator(复制粘贴完成)

命令行模式 1、java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml 2、Maven plugin(mybatis-generator-maven-plugin) 常用 2.1、mvn mybatis-generator:generate 2.2、${basedir}/src/main/resources/generatorConfig.xml 默认读取这个文件&#x…

mybatis自己学习的一些总结

以前一直在使用spring的JDBCTEMPLATE和hibernate做项目&#xff1b;两个都还不错&#xff0c;spring的jdbctemplate用起来比较麻烦&#xff0c;虽然很简单。而hibernate呢&#xff0c;用起来很好用&#xff0c;很方便&#xff0c;但是很多规矩&#xff0c;规则还有方法到现在都…

利用python模拟菜刀反弹shell绕过限制

有的时候我们在获取到目标电脑时候如果对方电脑又python 编译环境时可以利用python 反弹shell 主要用到python os库和sokect库 这里的服务端在目标机上运行 from socket import * from os import * ssocket(AF_INET,SOCK_STREAM)#IVP4 寻址 tcp协议 s.bind((,6666))#补丁端口 …

SpringBoot配置logback-spring.xml日志

SpringBoot配置logback-spring.xml日志 https://blog.csdn.net/qq_35618489/article/details/87709409 在SpringBoot新建 logback-spring.xml 配置文件&#xff0c;因为SPringBoot官方是推荐这个方式 内容&#xff0c;拷贝复制下来就可以了 <?xml version"1.0" e…

SSL的TCP通信

一切尽在代码中&#xff0c;额&#xff0c;自己测试的小例子&#xff0c;感觉很有用&#xff0c;做个记录。 服务器端&#xff1a; </pre><pre name"code" class"java">package com.mpc.test.clazz;import java.io.BufferedReader; import ja…

Java-ArrayList使用技巧---从第一个List中去除所有第二个List中与之重复的元素

需求&#xff1a;从 mAllList 中去除所有 mSubList 中与之重复的元素 测试数据&#xff1a;mAllList 中包含100000个无序无重复字符串&#xff0c;mSubList 中包含50000个无序无重复字符串 方法一、ArrayList中提供的removeAll方法&#xff08;效率最低&#xff09; mAllList.r…

JAVA对时间的几个处理小方法

获得两天之间相差的天数。 private static int daysBetween(Date date1, Date date2) {Calendar cal Calendar.getInstance();cal.setTime(date1);long time1 cal.getTimeInMillis();cal.setTime(date2);long time2 cal.getTimeInMillis();long between_days (time2 - time…

java反射的使用概览

额&#xff0c;研究过这个的人很多很多&#xff0c;但是我没有很深入的研究过&#xff0c;所以谁也拦不住我去研究研究&#xff0c;然后记录下来如有雷同那就雷同了请多多包涵。 首先是整个项目的结构&#xff1a; 使用到的类&#xff1a; package reflect.demo;public class D…

moodle3.7中文语言包

Moodle官方有中文语言包&#xff0c;但是还有没有翻译的&#xff0c;为了提高用户体验&#xff0c;可以将部分未翻译的应用在Moodle网站管理中自己修改。 具体步骤&#xff1a; 先确定需要修改的关键字&#xff0c;也就是网站中没有翻译成中文的文字在centos中定位到moodle网站…

如何在视图中启用thymeleaf

在HTML标签中引入一个属性 1 <html xmlns:th"http://www.thymeleaf.org"> 转载于:https://www.cnblogs.com/q2546/p/11093852.html

pushlet单播与多播

最近要弄一个消息推送的功能&#xff0c;在网上找了很多的关于pushlet的文章&#xff0c;虽然写的都很详细&#xff0c;但是本人看了以后却总觉得是模棱两可不知道如何下手&#xff0c;最终参考了这些文章中的一些内容&#xff0c;并结合官网的源代码&#xff0c;做了自己的修改…

两个小程序大概的了解一下java的线程

一、java的notify与wait package org.calonlan.soulpower;public class MyThreadTest implements Runnable {private String name;private Object prev;private Object self;public MyThreadTest(String name, Object prev, Object self) {super();this.name name;this.prev …

HttpContext HttpRuntime

问题引出 HttpContext.Current.Cache .VS. HttpRuntime.Cache HttpRuntime.Cache&#xff1a;获取当前应用程序的CacheHttpContext.Current.Cache&#xff1a;为当前HTTP请求获取Cache对象&#xff0c;跨线程可用&#xff0c;在APM模式或创建了子线程的场景中不能用HttpContext…

sudo apt-get常用命令

一、卸载 1. sudo apt-get autoclean 如果你的硬盘空间不大的话&#xff0c;可以定期运行这个程序&#xff0c;将已经删除了的软件包的.deb安装文件从硬盘中删除掉。如果你仍然需要硬盘空间的话&#xff0c;可以试试apt-get clean&#xff0c;这会把你已安装的软件包的安装包也…

Spring项目中使用webservice实现h5的websocket通信

一、在项目中建立一个webservice来做后台操作。 package org.calonlan.soulpower.websocket;import java.text.SimpleDateFormat; import java.util.Date;import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.we…

c++简单桶排序

c简单桶排序 题目一样&#xff0c;还是排序 桶排序是排序算法里比较快的 代码 注释 #include <bits/stdc.h> using namespace std; int main() {int b[100];//b[]的大小是你排的数字的最大值 1 int n;int k;memset(b,0,sizeof(b));//把b[]数组清零 cin >> n;for…

[连载型] Neutron 系列 (15): OpenStack 是如何实现 Neutron 网络 和 Nova虚机 防火墙的...

问题导读&#xff1a;1.Nova安全组是什么&#xff1f;2.Nova的是如何配置的?3.FWaas是什么&#xff1f;1. Nova 安全组1.1 配置 节点配置文件配置项说明controller/etc/nova/nova.confsecurity_group_api nova是的 nova secgroup* 命令使用的是 nova 安全组的 API/etc/neutro…

linux命令笔记

alias 查看或设置别名。 ualias 取消别名。 mkdir -p 创建目录及子目录。 vi/vim 编辑器。 seq -s 生成数字序列。 yum 解决linux下包管理工具rpm的安装软件依赖问题&#xff0c;例如&#xff1a;yum install lrzsz -y。 cp -apr 拷贝文件或目录。 tree -Ld打印目录结构…

LeetCode题解

题目是这样的&#xff1a;一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为“Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为“Finish”&#xff09;。问总共有多少条不同的路径&a…

Mysql的执行顺序与优化分析

编写顺序与执行顺序分析 一条完整的sql语句编写流程应该如下&#xff1a; select distinct 查询字段 from 表名 JOIN 表名 ON 连接条件 where 查询条件 group by 分组字段 having 分组后条件 order by 排序条件 limit 查询起始位置, 查询条数 但是在mysql实…