参考代码下载github:https://github.com/changwensir/java-ee/tree/master/spring4
AOP 术语
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="Spring4_AOP.aopAnnotation"/>
<!--使AspectJ注解起作用:自动为匹配的类生成代理对象-->
<aop:aspectj-autoproxy/>
</beans>ArithmeticCalculatorImpl在参见一篇博客http://blog.csdn.net/ochangwen/article/details/52557459日志切面
* 4. 编写切面类(把横切关注点的代码抽象到切面的类中):
* 4.1 一个一般的 Java 类
* 4.2 在其中添加要额外实现的功能.
*
* 5. 配置切面
* 5.1 切面必须是 IOC 中的 bean: 实际添加了 @Component 注解
* 5.2 声明是一个切面: 添加 @Aspect
* 5.3 声明通知: 即额外加入功能对应的方法!!.
@Aspect
@Component
public class LoggingAspect {
/**
* 重用切入点定义
* 定义一个方法,用于声明切入点表达式,一般地,该方法中再不需要添入其它的代码
*/
@Pointcut("execution(* Spring4_AOP.aopAnnotation.*.*(..))")
public void declareJoinPointerExpression() {}
//1、前置通知: 在目标方法开始之前执行(就是要告诉该方法要在哪个类哪个方法前执行)
//@Before("execution(public int Spring4_AOP.aopAnnotation.*.*(int ,int))")
@Before("declareJoinPointerExpression()")
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));
}
//2、后置通知:在目标方法执行后(无论是否发生异常),执行的通知
//注意,在后置通知中还不能访问目标执行的结果!!!,执行结果需要到返回通知里访问
//@After("execution(* Spring4_AOP.aopAnnotation.*.*(..))")
@After("declareJoinPointerExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends");
}
//无论连接点是正常返回还是抛出异常, 后置通知都会执行. 如果只想在连接点返回的时候记录日志, 应使用返回通知代替后置通知.
//3、返回通知:在方法正常结束后执行的代码,返回通知是可以访问到方法的返回值的!!!
//@AfterReturning(pointcut = "execution(* Spring4_AOP.aopAnnotation.*.*(..))", returning = "result")
@AfterReturning(value = "declareJoinPointerExpression()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " AfterReturning ends with " + result);
}
//4、异常通知:在目标方法出现异常 时会执行的代码,可以访问到异常对象:且可以!!指定在出现特定异常时在执行通知!!,如果是修改为nullPointerException里,只有空指针异常才会执行
// @AfterThrowing(pointcut = "execution(* Spring4_AOP.aopAnnotation.*.*(..))", throwing = "except")
@AfterThrowing(value = "declareJoinPointerExpression())", throwing = "except")
public void afterThrowing(JoinPoint joinPoint, Exception except){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " occurs exception " + except);
}
/**
* 5、环绕通知 需要携带 ProceedingJoinPoint 类型的参数.
* 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
* 且环绕通知必须有返回值, 返回值即为目标方法的返回值
*/
// @Around("execution(* Spring4_AOP.aopAnnotation.*.*(..))")
@Around("declareJoinPointerExpression()")
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 + " 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;
}
}
注意:
@Pointcut("execution(* Spring4_AOP.aopAnnotation.*.add(..)) ||execution(* Spring4_AOP.aopAnnotation.*.sub(..))")
public void declareJoinPointerExpression() {}
返回通知:?无论连接点是正常返回还是抛出异常,后置通知都会执行.如果只想在连接点返回的时候记录日志,应使用返回通知代替后置通知.3).环绕通知
@Test
public void testAOPAnnotation() {
//1、创建Spring的IOC的容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_AOP/applicationContext-aop.xml");
//2、从IOC容器中获取bean的实例
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
//3、使用bean
int result = arithmeticCalculator.div(3, 1);
System.out.println("result:" + result);
}
@Order(1)
@Aspect
@Component
public class ValidationAspect {
@Before("execution(public int Spring4_AOP.aopAnnotation.*.*(int ,int))")
public void validateArgs(JoinPoint joinPoint){
System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs()));
}
}日志切面,使用上面的那个类,只增加Order@Order(2)
@Aspect
@Component
public class LoggingAspect {
......
}
ArithmeticCalulator2与上面ArithmeticCalulator接口内容 一样
public class ArithmeticCalculatorImplXML implements ArithmeticCalculator2 {
public int add(int i, int j) {
return i + j;
}
public int sub(int i, int j) {
return i - j;
}
public int mul(int i, int j) {
return i * j;
}
public int div(int i, int j) {
return i / j;
}
}public class LoggingAspectXML {
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));
}
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends");
}
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends with " + result);
}
public void afterThrowing(JoinPoint joinPoint, Exception e){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " occurs excetion:" + e);
}
}
public class ValidationAspectXML {
public void validateArgs(JoinPoint joinPoint){
System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs()));
}
}<?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.xsd">
<!-- 配置 bean -->
<bean id="arithmeticCalculatorXML" class="Spring4_AOP.aopXML.ArithmeticCalculatorImplXML">
</bean>
<!-- 配置切面的 bean. -->
<bean id="loggingAspect" class="Spring4_AOP.aopXML.LoggingAspectXML">
</bean>
<bean id="validationAspect" class="Spring4_AOP.aopXML.ValidationAspectXML">
</bean>
<!-- 配置 AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="pointcut"
expression="execution(* Spring4_AOP.aopXML.ArithmeticCalculatorImplXML.*(int ,int))"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="validationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans> @Test
public void testXML() {
//1、创建Spring的IOC的容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_AOP/applicationContext-xml.xml");
//2、从IOC容器中获取bean的实例
ArithmeticCalculatorImplXML arithmeticCalculator = (ArithmeticCalculatorImplXML) ctx.getBean("arithmeticCalculatorXML");
//3、使用bean
int result = arithmeticCalculator.add(3, 3);
System.out.println("result:" + result);
arithmeticCalculator.div(10, 0);
}Spring4深入理解AOP02----AOP简介,AspectJ基于注解(5种通知,切面优先级)
原文:http://blog.csdn.net/ochangwen/article/details/52557724