spring之AOP(面向切面编程)

。_饼干妹妹 提交于 2019-12-04 07:28:20

一、简介

    何为AOP,通俗的将就是给某些方法执行之前、执行之后等动作发生的时候执行某些操作,在执行这些操作的时候可以获取执行方法的相关信息,简化程序开发中总是重复的东西,比如方法入参出参的日志打印,用户访问权限校验,事务控制等。

二、术语

    通知(advice):切面的工作被称为通知。通俗点:什么时候怎么干啥事。

        1.前置通知(before):在目标方法被调用之前调用通知功能。

        2.后置通知(after):在目标方法完成之后调用通知,此事不会关心方法的输出是什么。

        3.返回通知(after-returning):在目标方法成功执行之后调用通知。

        4.异常通知(after-throwing):在目标方法跑出异常后调用通知。

        5.环绕通知(around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

    连接点(joinpoint):使用通知的地方。

    切点(pointcut):匹配通知所要织入的一个或多个连接点。

    切面(aspect):通知和切点的结合定义切面的全部内容,它是什么,在何时何处完成其功能。

    引入(introduction):可以向现有的类添加新方法和属性。

    织入(weaving):把切面应用到目标对象并创建新的代理对象的过程。切面在制定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以织入:

        1.编译期:切面在目标类编译时织入,这种方式需要特殊的编译器,AspectJ的织入编辑器就是以这种方式织入切面的。

        2.类加载期:切面在目标类加载到JVM时织入,这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。

        3.运行期:切面在应用运行的某个时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象动态的创建一个代理对象,SpringAOP就是以这种方式织入切面的。

 

三、spring对AOP的支持

    spring提供了4种类型的AOP支持:

        1.基于代理的经典SpringAOP

        2.纯POJO切面

        3.@AspectJ注解驱动的切面

        4.注入式AspectJ切面

    前三种是springAOP实现的变体,SpringAOP构建在动态代理的基础之上,因此,spring对AOP的支持局限于方法拦截。

四、spring只支持方法界别的连接点

    因为spring是基于动态代理,所以孩子恩能够支持方法级别的aop。AspectJ和JBoss,除了方法切点,还提供了字段和构造器接入点。spring缺少字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改,而且他不支持构造器连接点,我们就无法再bean创建时应用通知。

五、切点表达式

    execution(* sundsystem.CompactDisc.playTrack(int))

    第一个* 返回任意类型

    sundsystem.CompactDisc 方法所属的类型

    playTrack 方法

    int 接受int类型的参数

六、demo

    注解:

package com.pz.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

@Aspect
@Component
public class LogAspect {

	private static Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	@Pointcut("execution(public * com.pz.service..*.*(..))")
	public void logPoint(){}
	
	@Before("logPoint()")
	public void logBefor(JoinPoint joinPoint){
		String method = joinPoint.getSignature().getName();
		Object [] args = joinPoint.getArgs();
		String param = JSON.toJSONString(args);
		logger.info("[前置通知][{}] param:{}", method, param);
	}
	
	@After("logPoint()")
	public void logAfter(JoinPoint joinPoint){
		String method = joinPoint.getSignature().getName();
		Object [] args = joinPoint.getArgs();
		String param = JSON.toJSONString(args);
		logger.info("[后置通知][{}] result:{}", method, param);
	}
	
	@AfterReturning(pointcut="logPoint()", returning="result")
	public void logAfterReturning(JoinPoint joinPoint, Object result){
		String method = joinPoint.getSignature().getName();
		String response = JSON.toJSONString(result);
		logger.info("[返回通知][{}] return:{}", method, response);
	}
	
	@AfterThrowing(pointcut="logPoint()", throwing="e")
	public void logAfterThrowing(JoinPoint joinPoint, Exception e){
		String method = joinPoint.getSignature().getName();
		logger.error("[异常通知][{}] exception:{}", method, e.getMessage());
	}
	
	@Around("logPoint()")
	public Object logArount(ProceedingJoinPoint pjp) throws Throwable{
		Object result = null;
		String param = JSON.toJSONString(pjp.getArgs());
		String method = pjp.getSignature().getName();
		try{
			logger.info("[环绕通知][{}] param:{}", method, param);
			result = pjp.proceed();
			logger.info("[环绕通知][{}] result:{}", method, JSON.toJSON(result));
		}catch(Exception e){
			logger.error("[环绕通知][{}] exception:{}", method, e.getMessage());
			 throw new RuntimeException(e);
		}
		logger.info("[环绕通知][{}] return:{}", method, JSON.toJSON(result));
		return result;
	}

}

    

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!