3.1.5 springAOP实现步骤

转自:https://www.kancloud.cn/lmkanyun/java_kuangjia/881881(感谢大佬的分享,本人搬运工)

  • AspectJ:Java 社区里最完整最流行的 AOP 框架.

  • 在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

使用步骤:

1.aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar

2.spring配置文件中添加:xmlns:aop="http://www.springframework.org/schema/aop"

3.要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素 aop:aspectj-autoproxy 。使AspectJ相关注解生效:当调用目标方法,跟Aspect中声明的方法相匹配的时候,AOP框架会自动的为目标方法所在的类创建代理对象

1.基于注解的方式实现springAOP:

1.创建切面类(LoggingAspect)。

@Aspect:声明当前类为切面类。

@Component:交给springIOC容器进行管理。

@Before:前置通知。

需要使用切点表达式:@Before("execution(* cn.li.service.impl.*.*(..))"),/**
 * 可以使用AspectJ表达式,对目标方法进行抽象概括。
 * 
 * execution(* cn.li.service.impl.*.*(String,..))
 * 
 * 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法 第二个* 表示当前包下所有的类 第三个* 表示所有的方法名称 ..
 * 表示匹配任意多个参数。 (String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
 * String,String 表示匹配参数为两个字符串的方法。
 */其中(Joinpoint)对象中封装了目标方法的一些信息,例如获取目标方法名称,获取目标方法参数等。

@Order(number):@Order 表示 配置多个切面之间的优先级问题 。 谁的值越小谁的优先级越高 。

@After:后置通知。使用方法与前置通知相同。注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。需要返回通知。

@AfterReturnning:返回通知,在方法正常之后之后执行的通知,可以拿到目标方法的返回结果。使用返回通知需要注意的是:指定returnning="result",afterReturnningAdvice(JoinPoint joinpoint,Object result)与方法入参位置的对象名称一致,否则会产生异常。

@AfterThrowing:异常通知,方法产生异常的时候,可以拿到异常信息。同样需要注意的是:指定throwing="e",与afterThrowingAdvice(JoinPoint joinpoint,Exception e)方法入参位置的异常对象名称一致。

@Around:环绕通知

具体代码实现如下:》》》》》
//当前类就是一个切面类
//想要一个类成为切面类,1.添加@Component 注释标注 当前类被springIOC容器所管理
//2.@Aspect表示当前类为一个切面类
//@Order 表示 配置多个切面之间的优先级问题  。 谁的值越小谁的优先级越高 。
//@Order(2)
//@Aspect
//@Component
public class LoggingAspect {
	// @Before表示前置通知。指的是在特定位置之前,去执行该方法
	// 通知 其实是切面类中一个具体的方法
	// JoinPoint 表示连接点
	/**
	 * 可以使用AspectJ表达式,对目标方法进行抽象概括。
	 * 
	 * execution(* cn.li.service.impl.*.*(String,..))
	 * 
	 * 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法 第二个* 表示当前包下所有的类 第三个* 表示所有的方法名称 ..
	 * 表示匹配任意多个参数。 (String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
	 * String,String 表示匹配参数为两个字符串的方法。
	 */
	//@Pointcut("execution(* cn.li.service.impl.*.*(..))")
	public void declareRepeatJoinPointExpression(){
		
	}

	//@Before("execution(* cn.li.service.impl.*.*(..))")
	public void beforeLog(JoinPoint joinpoint) {
		// 通过连接点对象可以获得调用目标方法的名称和参数
		// 获得方法名称。能拿到你要调用方法的名称
		String method = joinpoint.getSignature().getName();
		// 获得调用方法时传递的参数
		List arguments = Arrays.asList(joinpoint.getArgs());
		System.out.println("前置日志调用了方法" + method + "方法,参数是" + arguments);
	}

	// 注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。
	//@After("execution(* cn.li.service.impl.*.*(..))")
	public void afterLog(JoinPoint joinpoint) {
		String method = joinpoint.getSignature().getName();
		List arguments = Arrays.asList(joinpoint.getArgs());
		System.out.println("后置日志 。");
	}

	// 返回通知
	// 注意:返回通知 ,其实跟后置通知一样 。都是在目标方法执行完之后 才会被执行 。
	// returning="result" 名字 要跟参数列表中 Object 对象的名称一致 ,不然产生异常。
	//@AfterReturning(value = "execution(* cn.li.service.impl.*.*(..))", returning = "result")
	public void testAfterReturning(JoinPoint joinpoint, Object result) {
		String method = joinpoint.getSignature().getName();
		System.out.println("我是返回通知  。 我在目标方法核心业务执行完才会执行 。" + result);
	}
	//@AfterThrowing(value="execution(* cn.li.service.impl.*.count(..))",throwing="e")
	public void testAfterThrowing(JoinPoint joinpoint,Exception e){
		System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
	}
	//环绕通知 。   跟动态代理的代码很像。
	//@Around("declareRepeatJoinPointExpression()")
//	public void around(ProceedingJoinPoint pjp){
//		//声明一个Object 对象 用来表示 目标方法的返回值 。
//		Object result=null;
//		String method=pjp.getSignature().getName();
//		try {
//			System.out.println("我是前置日志 。。。"+method);
//			result = pjp.proceed();//调用proceed() 表示执行被代理类的目标方法。
//			System.out.println("我是返回通知"+method+result);
//		} catch (Throwable e) {
//			//Throwable 所有异常类跟错误类的父类 。Exception  Error ...
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//			System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
//		}
//		System.out.println("我是后置通知 。。。"+result+method);	
//	}
}
//@Order(1)
//@Aspect
//@Component
public class CheckAspect {
	
	//@Before("execution(* cn.li.service.impl.*.*(..))")
	public void checkBeforeLog(JoinPoint joinpoint){
		System.out.println("我是验证切面的前置通知 。");
	}
}

2.基于XML文件的方式实现springAOP:

<!-- 
		@Aspect  注解生效 。
		让注解生效,切面中的注解生效。
	当调用目标方法,跟Aspect中声明的方法相匹配的时候,
	AOP框架会自动的为目标方法所在的类创建代理对象。 
	
	 作用是让注解生效 ,当调用的方法,跟通知中声明的方法一致的时候。AOP框架会自动的为那个方法所在的类生成代理对象,然后在调用目标方法(之前或者之后)把通知中的方法加进去。
	-->
	<!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy> -->
	<!-- 配置切面 的bean -->
	<bean id="checkAspect" class="cn.li.aspect.CheckAspect"></bean>
	<bean id="loggingAspect" class="cn.li.aspect.LoggingAspect"></bean>
	<!-- 配置aop -->
	<aop:config>
		<!-- 配置切点表达式 -->
		<aop:pointcut expression="execution(* cn.li.service.impl.*.*(..))" id="pointcut"/>
		<aop:aspect ref="checkAspect" order="1">
			<aop:before method="checkBeforeLog" pointcut-ref="pointcut"/>
		</aop:aspect>
		<aop:aspect ref="loggingAspect" order="2">
			<aop:before method="beforeLog" pointcut-ref="pointcut"/>
			<aop:after method="afterLog" pointcut-ref="pointcut"/>
			<aop:after-returning method="testAfterReturning" returning="result" pointcut-ref="pointcut"/>
			<aop:after-throwing method="testAfterThrowing" throwing="e" pointcut-ref="pointcut"/>
			<!-- <aop:around method="around" pointcut-ref="pointcut"/> -->
		</aop:aspect>
	</aop:config>

猜你喜欢

转载自blog.csdn.net/qq_37570710/article/details/114039458