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);
}
}

(前置通知,后置通知)运行结果:

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


在日志切面做如下修改。在正常结束后执行的代码

/* 
* 在方法正常结束后执行的代码
* 返回通知是可以访问到方法的返回值的
*/
@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);
}

运行

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


异常通知

/*
* 在目标方法出现异常时会执行的代码
* 可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
*/
@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;
}