-
Spring 详解(三):AOP 面向切面的编程
2019-01-11 12:04:44AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性...AOP即面向切面编程,它通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。常用于日志记录,性能统计,安全控制,事务处理,异常处理等等。
中文名称:面向切面的编程
英文名称:Aspect Oriented Programming
正常程序执行流程都纵向执行流程:
- 在原有纵向执行流程中添加一个横切面
- 不需要修改原有程序代码,体现出程序的高扩展性
特点:
- 高扩展性
- 原有功能相当于释放了部分逻辑,让职责更加明确
用一句话来说面向切面的编程就是指:在原有纵向执行流程中,针对某一个或者某一些方法添加通知(前置通知和后置通知以及环绕通知),形成横切面过程就叫做面向切面编程。
1. AOP 面向切面编程术语
描述切面的常用术语有通知(advice)、切点(pointcut)和连接点(join point)等。下图展示了这些概念是如何关联在一起的。
1.1 通知 Advice
在AOP术语中,切面的工作被称为通知。 通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。Spring切面可以应用5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能;
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
1.2 连接点(Join point)
我们的应用可能有数以千计的时机应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
1.3 切点(Pointcut)
如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。
1.4 切面(Aspect)
切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。
1.5 引入(Introduction)
引入允许我们向现有的类添加新方法或属性。例如,我们可以创建一个Auditable通知类,该类记录了对象最后一次修改时的状态。这很简单,只需一个方法,setLastModified(Date),和一个实例变量来保存这个状态。然后,这个新方法和实例变量就可以被引入到现有的类中,从而可以在无需修改这些现有的类的情况下,让它们具有新的行为和状态。
1.6 织入(Weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:
- 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
- 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ 5的加载时织入(load-timeweaving,L TW)就支持以这种方式织入切面。
- 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面的。
2. Spring 对AOP的支持
Spring 提供了4种类型的AOP支持:
- 基于代理的经典Spring AOP(不推荐使用)
- 借助Spring AOP 命名空间,纯POJO切面
- @Aspect注解驱动的切面
- 注入Aspect切面
经典的Spring AOP十分笨重和过于复杂,它之间使用ProxyFactory Bean让人感觉厌烦。所以我们不推荐使用基于代理的经典的Spring AOP。
借助Spring的AOP命令空间,我们可以将存POJO转化为切面。实际上,这只是提供了满足切点条件时所要用的调用的方法。遗憾的是,这种技术需要XML的配置,但这的确是声明式地将对象转化为切面的简单方法。本质上还是使用Spring基于代理的AOP。
Spring借鉴了AspectJ的切面,已提供注解驱动的AOP。本质上它还是基于代理的AOP,但是编程模型机会与编写成熟的AspectJ注解切面完全一致。
AspectJ切面,提供了超过简单的方法调用(比如构造器或者属性拦截),AspectJ切面可以拦截对象更多的调用。
2. Spring在运行时通知对象
通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。如下图所示,代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。
直到应用需要被代理的bean时,Spring才创建代理对象。如果使用的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载所有bean的时候,Spring才会创建被代理的对象。因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入Spring AOP的切面。正如前面所探讨过的,通过使用各种AOP方案可以支持多种连接点模型。因为Spring基于动态代理,所以Spring只支持方法连接点。这与一些其他的AOP框架是不同的,例如AspectJ和JBoss,除了方法切点,它们还提供了字段和构造器接入点。Spring缺少对字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改。而且它不支持构造器连接点,我们就无法在bean创建时应用通知。但是方法拦截可以满足绝大部分的需求。如果需要方法拦截之外的连接点拦截功能,那么我们可以利用Aspect来补充Spring AOP的功能。
3. 借助Spring AOP 命名空间,纯POJO切面
每个通知都需要实现接口或者类
前置通知 public class AfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("切点方法返回对象: "+o); System.out.println("切点方法对象:"+method+ ", 方法名:"+method.getName()); if(method!=null && objects.length>0) System.out.println("切点方法参数:"+objects); else System.out.println("切点所在方法没有参数."); System.out.println("切点方法对象:"+o1); System.out.println("---------后置通知--------"); System.out.println(); } } 环绕通知 public class AroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("---------执行前置--------"); Object proceed = methodInvocation.proceed(); System.out.println("---------后置通知--------"); return proceed; } } 后置通知 public class BeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("切点方法对象:"+method+ ", 方法名:"+method.getName()); if(method!=null && objects.length>0) System.out.println("切点方法参数:"+objects); else System.out.println("切点所在方法没有参数."); System.out.println("切点方法对象:"+o.getClass()); System.out.println("---------执行前置--------"); } } 异常通知 只有当切点报异常后,才能触发异常通知 public class ThrowAdvice implements ThrowsAdvice{ public void afterThrowing(Method method, Object[] objects, Object target, Exception ex) throws Throwable{ //Do something with Exception System.out.println("执行异常 通过Schema-Based的方法执行异常: "+ex.getMessage()); } public void afterThrowing(Exception ex) throws Throwable{ //Do something with Exception System.out.println("执行异常 通过Schema-Based的方法执行异常2: "+ex.getMessage()); } }
定义切点(需要被切入的类)
public class Worker { public void doSomething(String name){ switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } public void doNoCutSomething(String name){ int i=1/0; switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } }
配置Spring配置文件在
<aop:config>
中配置<!--定义可以通过注解的形式扫描包--> <context:component-scan base-package="com.hust"/> <!--配置通知类对象,在切面中引入--> <bean id="beforeAdvice" class="com.hust.edu.advice.BeforeAdvice"/> <bean id="afterAdvice" class="com.hust.edu.advice.AfterAdvice"/> <bean id="aroundAdvice" class="com.hust.edu.advice.AroundAdvice"/> <bean id="worker" class="com.hust.edu.pointcut.Worker"/> <bean id="mythrows" class="com.hust.edu.advice.ThrowAdvice"></bean> <!--配置切面--> <aop:config> <!--配置切点--> <aop:pointcut id="pointcut" expression="execution(* com.hust.edu.pointcut.Worker.*(..))" /> <!--配置前置通知--> <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"/> <!--配置后置通知--> <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"/> <!--配置异常通知--> <aop:advisor advice-ref="mythrows" pointcut-ref="pointcut"/> <!--配置环绕通知--> <!--<aop:advisor advice-ref="aroundAdvice" pointcut-ref="pointcut"></aop:advisor>--> </aop:config> <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
表达式(在配置切面的切点中定义切点):
execution(* com.hust.edu.pointcut.Worker.doSomething(String))
- 通配符 * 匹配任意方法名、类名、一级包名
- 如果要匹配任意类型方法参数(…)
4. 使用AspectJ实现切面(XML配置方式)
新建构造通知类
public class MyParamAdvice implements ThrowsAdvice{ public void myExeception(Exception e){ System.out.println("---------执行异常通知--------"); System.out.println(e.getMessage()); } public void beforeCall(String name,int time){ System.out.println("name: "+name+" time: "+time); System.out.println("---------执行前置--------"); } public void beforeCal2(String name){ System.out.println("name: "+name); System.out.println("---------执行前置--------"); } public void afterCall(){ System.out.println("---------执行后置--------"); } public void afterCallReturning(){ System.out.println("---------后置通知Returning--------"); } public Object aroundCall(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("---------执行环绕前置--------"); Object proceed = joinPoint.proceed(); System.out.println("---------执行环绕后置--------"); return proceed; } }
定义切点(需要被切入的类)
public class ParamWorker { public void doSomething(String name,int time) throws Exception{ //抓取异常通知 //int i=5/0; switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } public void doSomething(String name) throws Exception{ //抓取异常通知 //int i=5/0; switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } public void doNoCutSomething(String name) throws Exception{ switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } }
配置Spring配置文件在
<aop:config>
中配置<bean id="myParamthrows" class="com.hust.edu.advice.MyParamAdvice"></bean> <!--AOP配置--> <aop:config> <aop:pointcut id="parampointcut" expression="execution(* com.hust.edu.pointcut.ParamWorker.doSomething(String,int)) and args(name,time)" /> <aop:pointcut id="parampointcut2" expression="execution(* com.hust.edu.pointcut.ParamWorker.doSomething(String)) and args(name)" /> <!--配置切面--> <aop:aspect ref="myParamthrows"> <!--<aop:after-throwing method="myExeception" pointcut-ref="parampointcut" throwing="e"/>--> <aop:before method="beforeCall" pointcut-ref="parampointcut" arg-names="name,time" /> <aop:before method="beforeCal2" pointcut-ref="parampointcut2" arg-names="name" /> <!--<aop:after method="afterCall" pointcut-ref="pointcut"/>--> <!--<aop:after-returning method="afterCallReturning" pointcut-ref="pointcut"/>--> <!--<aop:around method="aroundCall" pointcut-ref="pointcut"/>--> </aop:aspect> </aop:config> <bean id="paramWorker" class="com.hust.edu.pointcut.ParamWorker"/>
配置Spring配置文件(重点配置参数注入)
<aop:after>
后置通知:是否出现异常都执行<aop:after:returning>
后置通知:只有当切点正常执行时才执行后置通知<aop:after>
、<aop:after:returning>
和<aop:after:throwing>
的执行顺序和配置顺序有关- execution(* xxx(String,int)) and args(name,age)
- 其中args()括号里面的名称是自定义的顺序和切点方法参数的顺序一致
<aop:before arg-names="name,age">
arg-names的名称来源于expression=""中args(),名称必须一样。args()有几个参数,arg-names里面必须由几个参数。并且必须和通知方法参数名一样
4. 使用AspectJ实现切面(注解配置方式)
新建通知类
@Component @Aspect public class BetterMyAdvice { @Pointcut("execution(* com.hust.edu.pointcut.Worker.doSomething(String)) && args(name)") public void doSomething(String name){ } @AfterThrowing(value = "doSomething(String)", throwing = "e") public void myExeception(Exception e){ System.out.println("---------执行异常通知--------"); System.out.println(e.getMessage()); } @Before(value = "doSomething(String) && args(name)") public void beforeCall(String name){ System.out.println("name: "+name); System.out.println("---------执行前置--------"); } @After(value = "doSomething(String) && args(name)") public void afterCall(String name){ System.out.println("name: "+name); System.out.println("---------执行后置--------"); } @AfterReturning(value = "doSomething(String) && args(name)") public void afterCallReturning(String name){ System.out.println("name: "+name); System.out.println("---------后置通知Returning--------"); } @Around(value = "doSomething(String) && args(name)") public Object aroundCall(ProceedingJoinPoint joinPoint,String name) throws Throwable { System.out.println("---------执行环绕前置--------"); Object proceed = joinPoint.proceed(); System.out.println("---------执行环绕后置--------"); System.out.println("name: "+name); return proceed; } }
定义切点(需要被切入的类)
@Component public class Worker { @Pointcut(value = "execution(* com.hust.edu.pointcut.Worker.doSomething(String)) && args(name)") public void doSomething(String name) throws Exception{ //抓取异常通知 //int i=5/0; switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } public void doNoCutSomething(String name) throws Exception{ switch (name){ case "watch": System.out.println("----------watch TV---------"); break; default: break; } } }
配置Spring配置文件
<context:component-scan base-package="com.hust"/> <!--proxy-target-clas 如果为true使用cglib动态代理 false使用JDK动态代理--> <aop:aspectj-autoproxy proxy-target-class="true"/>
Spring不会自动寻找注解,必须告诉哪些包下的类有注解
实现步骤
- 在Spring配置文件中,设置注解在哪些保存。配置ComponentScan组件扫描
- 在Demo类中添加,
@Component
- 在切点方法上添加
@PointCunt
,定义切点 - 在通知类中配置
@Component
表示类交给Spring IOC容器管理@Aspect
表示相当于<aop-aspect>
表示切面
-
什么是AOP编程
2013-11-13 22:00:25面向切面编程Aspect Oriented Programming(AOP),...主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务面向切面编程Aspect Oriented Programming(AOP),是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
-
什么是面向对象切面编程
2015-03-30 13:43:07而面向对象编程主要是关注一些不是核心的业务,但又是必须的辅助功能,比如一个完整的系统中,记录平时系统运行抛出的异常,需要我们去记录,以便我们对系统尽快的修复,这就是我们常用的日志,如果对一下要求比较...面向对象编程主要注重核心业务,而面向对象编程主要是关注一些不是核心的业务,但又是必须的辅助功能,比如一个完整的系统中,记录平时系统运行抛出的异常,需要我们去记录,以便我们对系统尽快的修复,这就是我们常用的日志,如果对一下要求比较重要的数据操作,事务室不可少的,如金融系统,这样的数据很重要,每步操作都很重要,我们就应该用到事务处理。可根据你的系统数据的重要性,有选择的应用,好友一个常用的就是安全验证,它也是常用的,对于不同的页面,访问的身份也不一样,这就是我们常用的身份验证,以上这些不是针对特定的哪个业务模块的,可能是针对所有的模块,它们只是一些附加的功能,相对模块的主功能而言,如果在每个模块中夹杂这些不是核心业务的代码,看起来与核心业务有点关系,
面向方面编程(
Aspect-Oriented
就是把那些不是核心业务应该处理的代码提取出来,进行封装成模块化.来处理那些附加的功能代码
.(如日志,事务,安全验证)我们把这个模块的作用理解为一个切面,告诉我们它是一个功能模块.我们可以把它看成一个切面.说白了就是我们写一个类,在这个类中写一些处理在核心业务中起到同样效果的方法.这样大家应该明白了吧.专业的概念就是那么难理解.
第二个:连接点(Joinpoint),简单的理解就是在切面模块中定义的方法.就是上面定义类中的方法.
第三个:切入点(Pointcut).就是连接点的集合,就是一组方法的集合了. 以下几个就比较理解了,目标对象就是要处理的核心业务了.代理就更容易理解了,让一个代理去完成这个任务. -
关于AOP在JS中的实现与应用详解
2020-11-27 04:53:56AOP是OOP的延续,是软件开发中的一个热点,也是JAVA 中Spring框架的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可... -
spring boot aop做日志解决方案
2021-01-11 13:20:41意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务...AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
在spring AOP中业务逻辑仅仅只关注业务本身,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
相关注解介绍:
@Aspect:作用是把当前类标识为一个切面供容器读取@Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: final增强,不管是抛出异常或者正常退出都会执行import com.alibaba.fastjson.JSON; import ma.glasnost.orika.MapperFacade; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 写入请求日志 * * @author wu * @version 1.0 * @date 2020/8/11/011 */ @Configuration @Aspect public class ServiceAspect { private static Logger logger = LoggerFactory.getLogger(ServiceAspect.class); @Autowired private SysLogsMapper sysLogsMapper; @Autowired private MapperFacade mapperFacade; private ThreadLocal<SysLogs> threadLocal = new ThreadLocal<>(); private volatile boolean flag = false; //定义切入点,拦截controller包其子包下的所有类的所有方法 @Pointcut("execution(* com.xiao.platform.controller..*.*(..))") public void pointCut() { } //执行方法前的拦截方法 @Before("pointCut()") public void doBeforeMethod(JoinPoint point) { /* if (flag) { Signature signature = point.getSignature(); System.out.println(signature); SysLogs logs = new SysLogs(); //将当前实体保存到threadLocal threadLocal.set(logs); //String classMethod = signature.getName(); //RequestContextHolder:持有上下文的Request容器,获取到当前请求的request RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest httpServletRequest = sra.getRequest(); System.out.println("请求路径:" + httpServletRequest.getRequestURI().toString()); String requestURI = httpServletRequest.getRequestURI(); if ("/common/upload".equals(requestURI) || "/common/download".equals(requestURI) || "/user/logout".equals(requestURI)) { return; } //这一步获取到的方法有可能是代理方法也有可能是真实方法 Method m = ((MethodSignature) point.getSignature()).getMethod(); //判断代理对象本身是否是连接点所在的目标对象,不是的话就要通过反射重新获取真实方法 if (point.getThis().getClass() != point.getTarget().getClass()) { m = ReflectUtil.getMethod(point.getTarget().getClass(), m.getName(), m.getParameterTypes()); } //通过真实方法获取该方法的参数名称 LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer(); String[] parameterNames = paramNames.getParameterNames(m); //获取连接点方法运行时的入参列表 Object[] args = point.getArgs(); //将参数名称与入参值一一对应起来 Map<String, Object> params = new HashMap<>(); for (int i = 0; i < parameterNames.length; i++) { params.put(parameterNames[i], args[i]); } params.remove("request"); //删除名称为request的请求参数 String s; try { s = JSON.toJSONString(params); } catch (Exception e) { s = params.toString(); } logger.info("----------本次请求参数为---------:" + s); logs.setMethodName(m.getName()); //方法名称 logs.setRequestPath(httpServletRequest.getRequestURI()); //请求路径 logs.setRequestParams(s); }*/ } /** * 后置返回通知 * 这里需要注意的是: * 如果参数中的第一个参数为point,则第二个参数为返回值的信息 * 如果参数中的第一个参数不为point,则第一个参数为returning中对应的参数 * returning 限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为Object类型将匹配任何目标返回值 */ @AfterReturning(pointcut = "pointCut()", returning = "result") public void doAfterReturningAdvice1(JoinPoint point, Object result) { /* SysLogs logs = threadLocal.get(); if (flag) { logs.setCreatedAt(new Date()); String s = JSON.toJSONString(result); if (result != null) { ResponseEntity entity = mapperFacade.map(result, ResponseEntity.class); if (entity != null) { //可以转换成实体 logs.setResponseParams(characterSize(s)); } else { //不能转换实体 logs.setResponseParams(characterSize(s)); } } else { logs.setResponseParams(null); } sysLogsMapper.insert(logs); //移除当前log实体 threadLocal.remove(); } else if (logs != null) { threadLocal.remove(); }*/ } /** * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行 * * @param joinPoint 切入点 * @param e 异常信息 */ @AfterThrowing(pointcut = "pointCut()", throwing = "e") public void saveExceptionLog(JoinPoint joinPoint, Throwable e) { // 获取RequestAttributes RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); // 从获取RequestAttributes中获取HttpServletRequest的信息 HttpServletRequest request = (HttpServletRequest) requestAttributes .resolveReference(RequestAttributes.REFERENCE_REQUEST); SysLogs logs = threadLocal.get(); try { // 从切面织入点处通过反射机制获取织入点处的方法 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取切入点所在的方法 Method method = signature.getMethod(); // 获取请求的类名 String className = joinPoint.getTarget().getClass().getName(); // 获取请求的方法名 String methodName = method.getName(); methodName = className + "." + methodName; // 请求的参数 Map<String, String> rtnMap = converMap(request.getParameterMap()); // 将参数所在的数组转换成json String params = JSON.toJSONString(rtnMap); logs.setMethodName(methodName); // 请求方法名 logs.setResponseParams(stackTraceToString("异常名称为:" + e.getClass().getName() + "异常信息为:" + e.getClass().getName(), e.getMessage(), e.getStackTrace())); // 异常名称+异常信息 logs.setCreatedAt(new Date()); // 发生异常时间 sysLogsMapper.insert(logs); } catch (Exception e2) { e2.printStackTrace(); } } /** * 转换request 请求参数 * * @param paramMap request获取的参数数组 */ public Map<String, String> converMap(Map<String, String[]> paramMap) { Map<String, String> rtnMap = new HashMap<String, String>(); for (String key : paramMap.keySet()) { rtnMap.put(key, paramMap.get(key)[0]); } return rtnMap; } /** * 转换异常信息为字符串 * * @param exceptionName 异常名称 * @param exceptionMessage 异常信息 * @param elements 堆栈信息 */ public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) { StringBuffer strbuff = new StringBuffer(); for (StackTraceElement stet : elements) { strbuff.append(stet + "\n"); } String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString(); return message; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } /** * 控制字符长度 ,最多3000字符 * * @param str * @return */ private String characterSize(String str) { if (str.length() > 3000) { return str.substring(0, 3000); } return str; } /* */ /** * 后置最终通知(目标方法只要执行完了就会执行后置通知方法) *//* @After("pointCut()") public void doAfterAdvice(JoinPoint point) { System.out.println("后置通知执行了!!!!"); } */ /** * 环绕通知: * 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。 * 环绕通知第一个参数必须是org.aspectj.lang.Proceedingpoint类型 */ /* @Around(ExpGetResultDataPonit) public Object doAroundAdvice(Proceedingpoint proceedingpoint) { System.out.println("环绕通知的目标方法名:" + proceedingpoint.getSignature().getName()); processInputArg(proceedingpoint.getArgs()); try {//obj之前可以写目标方法执行前的逻辑 Object obj = proceedingpoint.proceed();//调用执行目标方法 processOutPutObj(obj); return obj; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; }*/ }
SysLogs:日志记录实体
-
Spring AOP在项目中的运用
2020-08-04 11:19:41意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务... -
-
Spring Aop详细教程
2019-01-20 18:01:05面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时... -
Spring中使用AOP
2017-09-21 15:26:13AOP概念 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个重要内容。...主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等 -
Visual Basic 2010 & .NET4 高级编程(第6版)-文字版
2013-03-21 08:54:516.3 .net中的异常处理 268 6.4 结构化异常处理的关键字 269 6.4.1 try、catch和finally关键字 270 6.4.2 throw关键字 271 6.4.3 抛出新的异常 272 6.4.4 exit try语句 273 6.4.5 嵌套的try结构 ... -
Visual.Basic.2010.&.NET4.高级编程(第6版)-文字版.pdf
2013-03-20 15:41:426.3 .net中的异常处理 268 6.4 结构化异常处理的关键字 269 6.4.1 try、catch和finally关键字 270 6.4.2 throw关键字 271 6.4.3 抛出新的异常 272 6.4.4 exit try语句 273 6.4.5 嵌套的try结构 274 ... -
用TCP/IP进行网际互联 第三卷:客户-服务器编程与应用(Linux/POSIX套接字版)--详细书签版
2012-10-12 14:44:577.2 小例子的重要性 55 7.3 隐藏细节 55 7.4 针对客户程序的过程库例子 56 7.5 connectTCP的实现 56 7.6 connectUDP的实现 57 7.7 构成连接的过程 57 7.8 使用例子库 60 7.9 DAYTIME服务 60 7.10 针对... -
关于@Aspect 注解的使用
2020-08-26 11:22:14意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务... -
AOP的运用即简单了解
2020-10-14 13:03:051.AOP的理解 1)....AOP的主要意图:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑中抽离出来,通过对于这些业务行为的分离,我们希望可以将他们独立到非指导业务逻辑的方法中 -
Spring的AOP
2020-04-20 23:04:44使用AOP,就不用在业务逻辑中实现与业务功能关系不大的代码(如日志、权限、异常处理、事务处理等),从而降低两种代码的耦合性,达到易于维护和重要的目的。 AOP的思想:假设每个对象都有记录日志这样的行为,... -
读Spring实战(第四版)概括—面向切面的Spring
2018-06-13 21:37:07AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性... -
Spring Boot学习(十七):Spring Boot的AOP教学,一看就会用
2020-06-13 23:52:19是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 主要功能 日志记录,性能统计,安全控制,事务... -
Aop的深入理解
2013-10-12 21:07:041.AOP是面向切面编程(Aspect Oriented Programming)是Spring框架中的一个重要内容,可对业务逻辑的各个部分进行隔离,降低耦合度,提高程序的可重用性。 2.是OOP的延续。 3.主要功能:将日志记录,性能统计,... -
对AOP的理解汇总
2013-03-22 18:38:341.AOP是面向切面编程(Aspect Oriented Programming)是Spring框架中的一个重要内容,可对业务逻辑的各个部分进行隔离,降低耦合度,提高程序的可重用性。 2.是OOP的延续。 3.主要功能:将日志记录,性能统计,... -
Spring07-(AOP)
2020-11-02 17:01:35AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性... -
Spring学习:AOP
2020-08-15 22:19:37什么是AOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理...将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为 -
Spring AOP
2020-08-14 11:14:27将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。 AOP中关键性... -
Spring学习笔记(二) AOP简介及实例
2019-01-07 11:36:56AOP 简介 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring ...主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。 Spring... -
spring之aop实例
2019-03-12 11:36:52面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring ...主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。 spring之aop实... -
Spring AOP详解
2018-11-26 12:02:00面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时... -
Spring4(4)——AOP面向切面
2019-09-28 06:29:201.面向切面基本概念 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring 框架中的一...主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等... -
SpringBoot使用@Aspect实现AOP
2021-01-29 10:50:58AOP(Aspect Oriented Programming,面向切面编程)是通过预编译方式和运行期动态代理实现...在Spring AOP中业务逻辑仅仅只关注业务本身,将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划 -
第九章 Spring4 AOP
2017-08-18 10:10:25AOP概念: 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring 框架中... 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。 ... -
10.AOP
2020-07-20 16:45:36AOP是OOP的延续,是软件开发中的一个热点,也是Spring]框架中的一个重要内容,是函数式编程的一种衍生范型。 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可...