概念

术语


AspectJ


Jar包

  • 实现AspectJ***
    aopalliance-1.0.jar
    aspectjweaver-1.6.8.jar
    spring-aop-4.0.0.RELEASE.jar
    <mark>spring-aspects-4.0.0.RELEASE.jar</mark>(没用到)

  • 实现spring创建类
    spring-context-4.0.0.RELEASE.jar
    spring-beans-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    commons-logging-1.1.1.jar
    spring-expression-4.0.0.RELEASE.jar



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

  • <!-- 设置要扫描的包 -->
    <context:component-scan base-package="vedio.aop"> </context:component-scan>
  • 使AspectJ注解起作用:自动为匹配的类生成***对象
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

基于注解的方式

  • 把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面
    @Aspect
    @Component - 切面首先是一个 IOC 中的bean

  • 声明该方法时一个前置<mark>通知</mark>:在目标方法开始之前执行
    @Before("executiong(public int 类全名.方法名(参数类型))")

    @Before("execution(public int vedio.proxy.Calculator.*(int , int ) )")
    所有(int, int )参数的方法

代码

<?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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- 设置要扫描的包 -->		
<context:component-scan base-package="vedio.aop">
</context:component-scan>
<!-- 使AspectJ注解起作用:自动为匹配的类生成***对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

package vedio.aop;

import org.springframework.stereotype.Component;

import vedio.proxy.Calculator;

@Component("calculator")
public class CalculatorImp_aop implements Calculator{

	@Override
	public int add(int a, int b) {
		return a+b;
	}

	@Override
	public int sub(int a, int b) {
		return a-b;
	}

	@Override
	public int mul(int a, int b) {
		return a*b;
	}

	@Override
	public int div(int a, int b) {
		return a/b;
	}

}

package vedio.aop;

import java.util.Arrays;

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

@Aspect
@Component
public class LoginingAspect {
	
	/** * 在方法执行之前执行的一段代码 */
	@Before("execution(public int vedio.proxy.Calculator.*(..) )")
	public void beforMethod( JoinPoint joinPoint ) {
		//获取方法名
		String methodName = joinPoint.getSignature().getName();
		//获取参数
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
	}
	
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//注意:这里不能获得结果,结果在返回其他通知里面
	/** * 无论被***方法是否执行,之后一定执行! */
	@After("execution(public int vedio.proxy.Calculator.*(..) )")
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
	}
	
	/** * 在方法正常结束时,执行的代码 * 返回通知时可以访问到方法的返回值的! */
	@AfterReturning(value = "execution(public int vedio.proxy.Calculator.*(..) )" , 
			returning = "result")
	public void afterReturningMethod(JoinPoint jointPoint , Object result) {
		String methodName = jointPoint.getSignature().getName();
		Object[] args = jointPoint.getArgs();
		System.out.println("The result of "+methodName+Arrays.toString(args)+" is " + result);
	}
	
	/** * 在目标方法出现异常时会执行的代码 * 可以访问到异常对象 * 且可以执行在出现特定异常时在执行通知代码 */
	@AfterThrowing(value = "execution(public int vedio.proxy.Calculator.*(..) )" , 
			throwing = "ex") 
	public void afterThrowingMethod(JoinPoint joinPoint , Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" occurs excetion:"+ex);
	}
	
// /**
// * 环绕通知需要携带 ProceedingJoinPoint 类型的参数,
// * 环绕通知类似于动态***的全过程: 
// * ProcedingJoinPoint 类型的参数可以决定是否执行目标的方法
// */
// @Around(value = "execution(public int vedio.proxy.Calculator.*(..) )")
// public Object aroundMthod(ProceedingJoinPoint pjd) {
// Object result = null ;
// String methodName = pjd.getSignature().getName();
// Object[] args = pjd.getArgs();
// 
// //前置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
// 
// try {
// //执行目标方法
// result = pjd.proceed(args);
// //后置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
// //返回通知
// System.out.println("The result of "+methodName+Arrays.toString(args)+" is " + result);
// } catch (Throwable e) {
// //后置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
// //异常通知
// System.out.println("The method "+methodName+" occurs excetion:"+e);
// }finally {
// }
// 
// return result; 
// }
}

	@Test
	public void test01() {
		ClassPathXmlApplicationContext pac = 
				new ClassPathXmlApplicationContext("vedio/beans-aop.xml");
		Calculator c = pac.getBean("calculator" , Calculator.class);
		int a = 4 ; 
		int b = 2 ; 
		int result =0 ; 
		
		result = c.add(a, b) ;
		
		result = c.sub(a, b);
		
		//异常
		result = c.div(a, 0);
		
	}

优先级

@Order(优先级)
<mark>值越小,优先级越高</mark>

	/** * 在方法执行之前执行的一段代码 */
	@Order(2)
	@Before("execution(public int vedio.proxy.Calculator.*(..) )")
	public void beforMethod( JoinPoint joinPoint ) {
		//获取方法名
		String methodName = joinPoint.getSignature().getName();
		//获取参数
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
	}
	
@Aspect
@Component
public class ValidatingAspect {
	
	@Order(1)
	@Before("execution(public int vedio.proxy.Calculator.*(..))")
	public void validatingArgs(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		//在执行之前
		//判断args是否符合条件....
		System.out.println(Arrays.toString(args)+" pass the validation of method "+ methodName);
	}
}

重用切点表达式

/*
 * 定义一个方法,用于声明切入点表达式,
 * 使用 @Pointcut 来声明切入点表达式
 * 后面的其他执行通知直接使用方法名来引用当前的切入点表达式。
 */
@Pointcut("execution(public int vedio.proxy.Calculator.*(..) )")
package vedio.aop;

import java.util.Arrays;

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

@Aspect
@Component
public class ValidatingAspect {
	
	@Order(1)
	@Before("vedio.aop.LoginingAspect.declareJoinPointExpression() ")
	public void validatingArgs(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		//在执行之前
		//判断args是否符合条件....
		System.out.println(Arrays.toString(args)+" pass the validation of method "+ methodName);
	}
}


package vedio.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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;

@Aspect
@Component
public class LoginingAspect {
	
	/* * 定义一个方法,用于声明切入点表达式, * 使用 @Pointcut 来声明切入点表达式 * 后面的其他执行通知直接使用方法名来引用当前的切入点表达式。 */
	@Pointcut("execution(public int vedio.proxy.Calculator.*(..) )")
	public void declareJoinPointExpression() {
		//一般的,该方法中不再需要添加其他代码。
	}
	
	/** * 在方法执行之前执行的一段代码 */
	@Order(2)
	@Before("declareJoinPointExpression() ")
	public void beforMethod( JoinPoint joinPoint ) {
		//获取方法名
		String methodName = joinPoint.getSignature().getName();
		//获取参数
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
	}
	
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//注意:这里不能获得结果,结果在返回其他通知里面
	/** * 无论被***方法是否执行,之后一定执行! */
	@After("declareJoinPointExpression() ")
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
	}
	
	/** * 在方法正常结束时,执行的代码 * 返回通知时可以访问到方法的返回值的! */
	@AfterReturning(value ="declareJoinPointExpression() ", 
			returning = "result")
	public void afterReturningMethod(JoinPoint jointPoint , Object result) {
		String methodName = jointPoint.getSignature().getName();
		Object[] args = jointPoint.getArgs();
		System.out.println("The result of "+methodName+Arrays.toString(args)+" is " + result);
	}
	
	/** * 在目标方法出现异常时会执行的代码 * 可以访问到异常对象 * 且可以执行在出现特定异常时在执行通知代码 */
	@AfterThrowing( value = "declareJoinPointExpression() " , 
			throwing = "ex") 
	public void afterThrowingMethod(JoinPoint joinPoint , Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" occurs excetion:"+ex);
	}
	
// /**
// * 环绕通知需要携带 ProceedingJoinPoint 类型的参数,
// * 环绕通知类似于动态***的全过程: 
// * ProcedingJoinPoint 类型的参数可以决定是否执行目标的方法
// */
// @Around(value = "execution(public int vedio.proxy.Calculator.*(..) )")
// public Object aroundMthod(ProceedingJoinPoint pjd) {
// Object result = null ;
// String methodName = pjd.getSignature().getName();
// Object[] args = pjd.getArgs();
// 
// //前置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
// 
// try {
// //执行目标方法
// result = pjd.proceed(args);
// //后置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
// //返回通知
// System.out.println("The result of "+methodName+Arrays.toString(args)+" is " + result);
// } catch (Throwable e) {
// //后置通知
// System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
// //异常通知
// System.out.println("The method "+methodName+" occurs excetion:"+e);
// }finally {
// }
// 
// return result; 
// }
}

基于配置文件的方式

<?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" 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">

<!-- 配置bean -->
<bean id="calculator" class="vedio.aop.CalculatorImp_aop"></bean>

<!-- 配置切面bean -->
<bean id="loginingAspect" class="vedio.aop.LoginingAspect_xml"></bean>
<bean id="validatingAspect" class="vedio.aop.ValidatingAspect_xml"></bean> 
<!-- 配置AOP -->
<aop:config >
	<!-- 配置切点 - 表达式 -->
	<aop:pointcut expression="execution(int vedio.proxy.Calculator.*(int ,int ))" id="calcPointcut" />
	<!-- 配置切面、通知 -->
 	<aop:aspect order="1" ref="validatingAspect" >
		<aop:before method="validatingArgs" pointcut-ref="calcPointcut" /> 
	</aop:aspect>
	<aop:aspect order="2" ref="loginingAspect">
		<!-- 前置 -->
		<aop:before method="beforMethod" pointcut-ref="calcPointcut"/>
		<!-- 后置 -->
		<aop:after method="afterMethod" pointcut-ref="calcPointcut"/>
		<!-- 返回 -->
		<aop:after-returning method="afterReturningMethod" pointcut-ref="calcPointcut" returning="result"/>
		<!-- 异常 -->
		<aop:after-throwing method="afterThrowingMethod" pointcut-ref="calcPointcut" throwing="ex"/>
		<!-- 环绕 <aop:around method="aroundMethod" pointcut-ref=""/> -->
	</aop:aspect>
</aop:config>

</beans>

package vedio.aop;

import java.util.Arrays;

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


public class ValidatingAspect_xml {

	public void validatingArgs(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		//在执行之前
		//判断args是否符合条件....
		System.out.println(Arrays.toString(args)+" pass the validation of method "+ methodName);
	}
}

package vedio.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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;

public class LoginingAspect_xml {
	


	public void beforMethod( JoinPoint joinPoint ) {
		//获取方法名
		String methodName = joinPoint.getSignature().getName();
		//获取参数
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) + " begin");
	}
	

	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		System.out.println("The method "+ methodName+Arrays.toString(args) +" is end");
	}
	

	public void afterReturningMethod(JoinPoint jointPoint , Object result) {
		String methodName = jointPoint.getSignature().getName();
		Object[] args = jointPoint.getArgs();
		System.out.println("The result of "+methodName+Arrays.toString(args)+" is " + result);
	}

	public void afterThrowingMethod(JoinPoint joinPoint , Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" occurs excetion:"+ex);
	}

}

package video;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import vedio.proxy.Calculator;

public class Test_AOP_xml {
	@Test
	public void test01() {
		ClassPathXmlApplicationContext pac = 
				new ClassPathXmlApplicationContext("vedio/beans-aop-xml.xml");
		Calculator c = pac.getBean("calculator" , Calculator.class);
		int a = 4 ; 
		int b = 2 ; 
		int result ; 
		result = c.add(a, b) ;
		result = c.sub(a, b);
		result = c.div(a, 0);
	}
}