Spring 学习笔记 —— AOP

AOP 简介

AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
AOP 的好处:
每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
业务模块更简洁, 只包含核心业务代码.

AOP 术语 

切面(Aspect):  横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
通知(Advice):  切面必须要完成的工作
目标(Target): 被通知的对象
代理(Proxy): 向目标对象应用通知之后创建的对象
连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置
切点(pointcut):每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

AspectJ

AspectJ:Java 社区里最完整最流行的 AOP 框架.
在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

使用AOP(@AspectJ注解)

		
			org.springframework
			spring-aop 
			4.3.10.RELEASE
		
		
			org.springframework
			spring-aspects
			4.3.10.RELEASE
		
		


		
	
	
	
	
	

package cn.fg.aop;

import java.util.Arrays;

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.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(1)   //切面优先级,存在多个切面时,值越小优先级越高,默认优先级是Integer.MAX_VALUE

//切面注解,开启时有效,若只在父容器中开启切面,则切面只会在包下的bean被调用时进行切入,
//若在子容器中开启切面,由于子容器可以调用父容器的bean,所以在可在所有bean切入
@Aspect    

@Component  //必须向ioc容器中注入bean
public class LoggingAspect { //日志切面类
	
	/**
	 * execution表达式语法
	 * execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
	 * modifier-pattern:修饰符匹配,如public
	 * ret-type-pattern:返回值匹配,如int或全路径类名,可以为*表示任何返回值
	 * declaring-type-pattern:类路径匹配(需要和name-pattern配合使用)
	 * 	1. cn.fg.aop.ArithmeticCalculator.  精准的类路径匹配
	 *  2. cn.fg.aop.*. cn.fg.aop包名下的任意类匹配
	 *  3. cn.fg..ArithmeticCalculator. cn.fg及子包下的ArithmeticCalculator匹配
	 *  4. cn.fg..*. cn.fg及子包下的任意类匹配
	 * name-pattern:方法名匹配,如add;可以为 *表示所有方法或者set*代表以set开头的所有方法
	 * param-pattern:参数类型匹配,如int,int 多个参数逗号分隔;可以为*表示任意参数类型,如*,int; ..表示零个或多个任意参数
	 * throws-pattern:异常类型匹配
	 * 表达式中的?号表示是可选的,所以最短的表达式为execution(* *(..))
	 */

	//前置通知,在目标方法之前执行
	@Before("execution(* cn.fg..*.*(..))")
	public void beforeMethod(JoinPoint joinPoint){
		//在这里写切入的逻辑
		String methodName = joinPoint.getSignature().getName();  //目标的方法名
		Object [] args = joinPoint.getArgs();  //目标方法的参数
		Object targetObject = joinPoint.getTarget();  //目标对象
		Object proxyObject = joinPoint.getThis(); //AOP框架为目标对象生成的代理对象
		System.out.println("methodName=" + methodName);
		System.out.println("args=" + Arrays.asList(args));
		System.out.println("targetObject=" + targetObject);
		System.out.println("proxyObject=" + proxyObject);
	}
	
	//定义公共execution表达式
	@Pointcut("execution(* cn.fg..*.*(..))")
	public void declareJointPointExpression(){}
	
	//后置通知,在目标方法执行后执行(即使目标方法抛出异常也会执行)
	//在后置通知中不能拿到目标方法返回的结果
	@After("declareJointPointExpression()") //使用公共execution
	//@After("cn.fg.aop.VlidationAspect.declareJointPointExpression()") 引用其他切面的表达式
	public void afterMethod(JoinPoint joinPoint){
		System.out.println("@After.........................");
	}
	
	/**
	 * 在方法法正常结束受执行的代码
	 * 返回通知是可以访问到方法的返回值的!
	 * returning:设置接收返回值的参数名,名字随便取要与接收的参数名对应=Object result
	 */
	@AfterReturning(value="execution(* cn.fg..*.*(..))",returning="result")
	public void afterReturning(JoinPoint joinPoint, Object result){
		System.out.println("返回值="+result);
		System.out.println("@AfterReturning.......................");
	}
	
	/**
	 * 在目标方法出现异常时会执行的代码.
	 * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
	 * throwing:设置接收异常的参数名称,名字随便取要与接收的参数名对应=Exception e
	 */
	@AfterThrowing(value = "execution(* cn.fg..*.*(..))", throwing = "e")
	public void afterThrowing(JoinPoint joinPoint, Exception e) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + " occurs excetion:" + e);
	}
	
	/*
	 * aop通知结构
	 *  try {
	 *		//前置通知
	 *		int result = 0;
	 *		//返回通知
	 *	} catch (Exception e) {
	 *		//异常通知
	 *	}
	 *	//后置通知
	 */
	
	
	/**
	 * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 
	 * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
	 * 且环绕通知必须有返回值, 返回值即为目标方法的返回值
	 */
	@Around("execution(* cn.fg..*.*(..))")
	public Object aroundMethod(ProceedingJoinPoint pjd){
		
		Object result = null;
		String methodName = pjd.getSignature().getName();
		
		try {
			//前置通知
			System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
			//执行目标方法
			result = pjd.proceed();
			//返回通知
			System.out.println("The method " + methodName + " ends with " + result);
		} catch (Throwable e) {
			//异常通知
			System.out.println("The method " + methodName + " occurs exception:" + e);
			throw new RuntimeException(e);
		}
		//后置通知
		System.out.println("The method " + methodName + " ends");
		
		return result;  //可以修改返回值
	}


    //切入点表达式可以通过操作符 && || !结合起来
    //@Pointcut("execution(* Spring4_AOP.aopAnnotation.*.add(..)) || execution(* Spring4_AOP.aopAnnotation.*.sub(..))")
	
}

使用AOP(xml)

仅了解,可以这样配,省略。。。。。

你可能感兴趣的:(spring)