天天看点

Spring AOP(一)——基于注解的方式步骤

步骤

1.导入jar包:

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

spring-aop-4.2.4.RELEASE.jar

spring-aspects-4.2.4.RELEASE.jar

spring-beans-4.2.4.RELEASE.jar

spring-context-4.2.4.RELEASE.jar

spring-core-4.2.4.RELEASE.jar

spring-expression-4.2.4.RELEASE.jar

com.springsource.org.apache.commons.logging-1.1.1.jar

2.在配置文件中加入aop 的命名空间

xmlns:aop=“http://www.springframework.org/schema/aop”

3.基于注解的方式

a.在配置文件中加入如下配置:
           
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop.impl"></context:component-scan>
           
<!-- 使用AsoectJ 注解起作用:自动匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
           
b.把横切关注点的代码抽象到切面的类中
	i.首先是需要把该类放入到IOC容器中,即加入@Component 注解
	ii.切面还需要加入@Aspect 注解
           
@Aspect
@Component
public class LoggingAspect {
}
           
c.在类中声明各种通知
	i.声明一个方法
	ii.在方法前加入一个@Before/@After/@Around/@AfterReturning/@AfterThrowing 注解
           
  • 前置通知@Before
@Aspect
@Component
public class LoggingAspect {
	
	//声明该方法是一个前置通知,在目标方法之前执行
	@Before("execution(* com.atguigu.spring.aop.impl.*.*(..))")
	public void beforeMethod() {
		System.out.println("The method begins");
	}
}
           
d.可以在通知方法中声明一个类型为 JoinPoint 的参数,然后就能访问链接细节,入方法名称和参数值
           
@Aspect
@Component
public class LoggingAspect {
	
	//声明该方法是一个前置通知,在目标方法之前执行
	@Before("execution(* com.atguigu.spring.aop.impl.*.*(..))")
	public void beforeMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method "+ methodName +" begins with" + args);
	}
}
           
  • 后置通知@After
/**
     *目标方法执行后(无论是否发生异常),执行的通知
	 *在后置通知中还不能访问目标方法执行的结果
	 */
	@After("execution(* com.atguigu.spring.aop.impl.*.*(..))")
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method "+ methodName +" end ");
	}
           
  • 返回通知
//在方法正常结束后执行的代码,可以访问到方法的返回值
	@AfterReturning(value = "execution(* com.atguigu.spring.aop.impl.*.*(..))" , returning = "result")
	public void afterReturning(JoinPoint joinPoint,Object result) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName+ " end result:" + result);
	}
           
  • 异常通知
//在方法出现异常时会执行的代码,可以访问到异常对象,且可以指定再出现特定异常时在执行通知代码
	@AfterThrowing(value = "execution(* com.atguigu.spring.aop.impl.*.*(..))",throwing = "ex")
	public void afterThrowing(JoinPoint joinPoint,Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName +" occurs exception:" + ex );
	}
           
  • 环绕通知
/**
	 * 环绕通知需要携带ProceedingJoinPoint 类型参数,
	 *环绕通知类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
	 *且环绕通知必须有返回值,返回值即为目标方法的返回值
	 */
	@Around("execution(* com.atguigu.spring.aop.impl.*.*(..)))")
	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 + " end with:" + result);
		} catch (Throwable e) {
			System.out.println("The method " + methodName + " occurs exception:" + e);
			
		}
		System.out.println("The method " + methodName + " ends ");
		return 100;
		
	}

           

这里我们可以看到每次申明通知时都要写:

所以我们可以把它提取出来

- 定义一个方法,用于声明切入点表达式,该方法中在不需要填入其他的代码
 - 使用@Pointcut 来声明切入点表达式,后面的其他通知直接使用方法名来引用当前的切入点表达式
           
@Pointcut("execution(* com.atguigu.spring.aop.impl.*.*(..)))")
	public void declareJoinPointExpression() {}
	
	@Before("declareJoinPointExpression()")
	public void beforeMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method "+ methodName +" begins with" + args);
	}
           
- 如果是外面的类引用该表达式则使用  类名.方法名
           
@Aspect
@Component
public class VlidationAspect {
	@Before("LoggingAspect.declareJoinPointExpression()")
	public void validataArgs(JoinPoint joinPoint) {
		System.out.println("--->validate:" +Arrays.asList(joinPoint.getArgs()));
	}
}
           

另外:如果有多个切面,我们可以使用@Order 指明切面的优先级

@Order(1)
@Aspect
@Component
public class VlidationAspect {
}
           
@Order(2)
@Aspect
@Component
public class LoggingAspect {
}