欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前置通知

程序员文章站 2022-05-03 13:00:56
...

Spring 中启用 AspectJ 注解支持

要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jaraspectj.weaver.jar spring-aspects.jar

aop Schema 添加到 <beans> 根元素中.

要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要Bean 配置文件中定义一个空的 XML 元素 <aop:aspectj-autoproxy>

Spring IOC 容器侦测到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.

AspectJ 注解声明切面

要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.

AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java .

通知是标注有某种注解的简单的 Java 方法.

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

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

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

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

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

@Around: 环绕通知, 围绕着方法执行

前置通知

前置通知:在方法执行之前执行的通知

前置通知使用 @Before 注解, 并将切入点表达式的值作为注解值.

前置通知

利用方法签名编写 AspectJ 切入点表达式

最典型的切入点表达式时根据方法的签名来匹配各种方法:

execution * com.atguigu.spring.ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 中声明的所有方法,第一个 * 代表任意修饰符及任意返回值. 第二个 * 代表任意方法. .. 匹配任意数量的参数. 若目标类与接口与该切面在同一个包中, 可以省略包名.

execution public * ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 接口的所有公有方法.

execution public double ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 返回 double 类型数值的方法

execution public double ArithmeticCalculator.*(double, ..): 匹配第一个参数为 double 类型的方法, .. 匹配任意数量任意类型的参数

execution public double ArithmeticCalculator.*(double, double): 匹配参数类型为 double, double 类型的方法.

合并切入点表达式

AspectJ , 切入点表达式可以通过操作符 &&, ||, ! 结合起来.

前置通知

让通知访问当前连接点的细节

可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值.

前置通知

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<!-- 开启注解扫描 -->
	<context:component-scan base-package="com.learn.spring.aspectJ"></context:component-
scan>
	
	<!-- 基于注解开发开启aop自动代理-->
	<aop:aspectj-autoproxy/>
</beans>
package com.learn.spring.aspectJ;

public interface ArithmeticCalculator {
	public  int add(int i, int j );
	public  int sub(int i, int j );
	public  int mul(int i, int j );
	public  int div(int i, int j );
} 
package com.learn.spring.aspectJ;

import org.springframework.stereotype.Component;

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j ;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j ;
		return result;	
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j ;
		return result;
	}

	@Override
	public int div(int i, int j) {
		int result = i / j ;
		return result;
	}
	
}
package com.learn.spring.aspectJ;

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;

/**
 * 日志切面
 */
@Component  //标识为组件
@Aspect  //标识为切面
@Order(3)  //指定切面的优先级. 值越小,优先级越高. 标注@Order的切面比不标注@Order切面的优先级高
public class LoggingAspect {

	/**
	 * 通知:  前置   后置   返回   异常  环绕
	 */	
		
	/**
	 * 前置通知: 在方法执行之前执行.
	 * JoinPoint:连接点对象  包含了连接点相关的信息:方法名   方法的参数等....
	 */
	//@Before("execution(public int com.learn.spring.aspectJ.ArithmeticCalculator.add(int,int))")
	//@Before("execution(public int com.learn.spring.aspectJ.ArithmeticCalculator.*(int,int))")
	//任意修饰符任意返回值  com.learn.spring.aspectJ包下的任意类的任意方法   任意参数
	//@Before("execution(* com.learn.spring.aspectJ.*.*(..))")
	@Before("suibian()")
	public void beforeMethod(JoinPoint joinPoint){
		//获取方法名:
		String methodName = joinPoint.getSignature().getName();
		//获取参数
		Object [] args = joinPoint.getArgs();
		System.out.println("The method "+methodName+" begins with "+ Arrays.asList(args));
	}
	
}

package com.learn.spring.aspectJ;

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

public class Main {
	public static void main(String[] args) {
		ApplicationContext ctx = 
				new ClassPathXmlApplicationContext("spring-aspectJ.xml");
		ArithmeticCalculator ac = 
				(ArithmeticCalculator)ctx.getBean("arithmeticCalculatorImpl");
		System.out.println(ac.getClass().getName());
		int result = ac.div(2, 1);
		System.out.println("AspectJ-result====>:"+result);
	}
}