spring (学习记录)AOP:前置,后置,返回,异常,环绕通知

AspectJ:java社区最完整最完善的AOP框架;

AspectJ支持的5种类型的通知注解:

@Before:前置通知,在方法执行之前执行

@After:后置通知,在方法执行之后执行

@AfterRunning:返回通知,在方法返回结果后执行

@AfterThrowing:异常通知,在方法抛出异常之后执行

@Around:环绕通知,围绕着方法执行
  
Spring也有自身的AOP框架。可以使用基于AspectJ注解或基于XMl配置的AOP。
注解方式:

1、除spring基本jar包,额外需要加入jar包:aopalliance、aspectj.weaver、aop.RELRESE、aspects.RELEASE

2、配置自动扫描
配置文件

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

       <!-- 配置自动扫描的包-->
       <context:component-scan base-package="com.spring.aop.impl"></context:component-scan>
       <!-- 使AspectJ注释起作用:自动为匹配的类生成代理对象 -->
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

创建接口:

package com.spring.aop.impl;

import javax.swing.JInternalFrame;
public interface CalCulator {
       int add(int i,int j);
       int sub(int i,int j);
       
       int mul(int i,int j);
       int div(int i,int j);
}

创建实现类:

package com.spring.aop.impl;

import org.springframework.stereotype.Component;

@Component
public class CalCulatorImpl implements CalCulator {

	@Override
	public int add(int i, int j) {
		// TODO Auto-generated method stub
		int result=i+j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		// TODO Auto-generated method stub
		int result=i-j;
		return result;
	}

	@Override
	public int mul(int i, int j) {
		// TODO Auto-generated method stub
		int result=i*j;
		return result;
	}

	@Override
	public int div(int i, int j) {
		// TODO Auto-generated method stub
		int result=i/j;
		return result;
	}

}

创建日志切面:

package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:需要把该类放入到IOC容器中,声明为一个切面
@Aspect
@Component
public class LoggingAspect {
	   //声明该方法是一个前置通知:在目标方法开始之前执行 可以指定方法名,
	  // 如果那个接口里的所有方法都要加,那就直接*号,其他的也可以用*号代替
	   @Before("execution(* com.spring.aop.impl.*.*(int, int))")
       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("execution(* com.spring.aop.impl.*.*(int,int))")
	   public void afterMethod(JoinPoint joinPoint) {
		   String methodName=joinPoint.getSignature().getName();
		   System.out.println("The method "+methodName+" ends");
		   
	   }
	   
}

运行主类:

package com.spring.aop.impl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	
       public static void main(String[] args) {
		//1.加入spring的IOC容器
    	   ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    	   //2.从IOC容器中获取bean 的实例
    	   CalCulator calCulator=ctx.getBean(CalCulator.class);
    	   
    	   //3.使用bean
    	   int result=calCulator.add(3, 6);
    	   System.out.println("result: "+result);
    	   
    	   result=calCulator.div(2, 1);
    	   System.out.println("result: "+result);
	}
}

(前置通知,后置通知)运行结果:
在这里插入图片描述
在日志切面做如下修改。在正常结束后执行的代码

/* 
	   * 在方法正常结束后执行的代码
	   * 返回通知是可以访问到方法的返回值的
	   */
	   @AfterReturning(value="execution(* com.spring.aop.impl.*.*(..))",
			   returning="result")
	   
	   public void afterReturning(JoinPoint joinPoint,Object result) {
		   String methodName =joinPoint.getSignature().getName();
		   System.out.println("The method"+methodName+" ends with "+result);
	   }

运行
在这里插入图片描述
异常通知

 /*
	    * 在目标方法出现异常时会执行的代码
	    * 可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
	   */
	   @AfterThrowing(value="execution(* com.spring.aop.impl.*.*(..))",
			   throwing="ex")
	   public void afterThrowing(JoinPoint joinPoint,Exception ex) {
		   String methodName=joinPoint.getSignature().getName();
		   System.out.println("The method "+methodName+" occurs excetion:"+ex);
	   }

环绕通知

/*
	    * 环绕通知需要携带ProceedingJoinPoint类型的参数
	    * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
	    * 且环绕通知必须要有返回值,返回值即为目标方法的返回值
	   */
	   //环绕通知是最强的,可以实现以上四种通知
	   
	   @Around("execution(* com.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 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;
	   }

猜你喜欢

转载自blog.csdn.net/qq_37774171/article/details/86528612
今日推荐