第一步:在springMvc的xml文件里配置
<context:component-scan base-package="com.aspectJ"/>
<aop:aspectj-autoproxy/>
第二步:编写Aop配置的java类
package com.aspectJ;
/**
* Created by tang on 2018/4/25.
*/
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 注解声明一个aspectj,比较测试5种通知
*/
/**
* 把这个类声明为一个切面:
* 1. 使用注解“@Component”把该类放入到IOC容器中
* 2. 使用注解“@Aspect”把该类声明为一个切面
* <p>
* 设置切面的优先级:
* 3. 使用注解“@Order(number)”指定前面的优先级,值越小,优先级越高
*/
//@Order(1)
@Aspect
@Component
public class AspectJAdvice {
/**
* 表达式例子如下:
* 任意公共方法的执行:
* execution(public * *(..))
* 任何一个以“set”开始的方法的执行:
* execution(* set*(..))
* AccountService 接口的任意方法的执行:
* execution(* com.xyz.service.AccountService.*(..))
* 定义在service包里的任意方法的执行:
* execution(* com.xyz.service.*.*(..))
* 定义在service包和所有子包里的任意类的任意方法的执行:
* execution(* com.xyz.service..*.*(..))
* 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
* execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
* 在多个表达式之间使用 ||,or表示 或,使用 &&,and表示 与,!表示 非.例如:
* <aop:config>
* <aop:pointcut id="pointcut" expression="(execution(* com.ccboy.dao..*.find*(..))) or (execution(* com.ccboy.dao..*.query*(..)))"/>
* <aop:advisor advice-ref="jdbcInterceptor" pointcut-ref="pointcut" />
* </aop:config>
*/
@Pointcut("execution(* com.service.ITradeCompanyService.*(..))")//调用ITradeCompanyService里面的任何方法都算是这个切入点
public void pointCutMethod() {
// System.out.println("我是pointCutMethod===================================================");
// System.out.println("我是切入点,即需要增强的方法");
}
/**
* 可以在通知方法中声明一个类型为 JoinPoint 的参数。然后就能访问链接细节。如方法名称和参数值
* 声明该方法是一个前置通知:在目标方法开始之前执行
*
* @param joinPoint
*/
@Before("execution(* com.controllers.*.*(..))")//调用controllers包里面的任何controller类里面的方法都会触发此方法
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("我是前置通知的方法:");
//获取方法名称
String methodName = joinPoint.getSignature().getName();
//获取参数值
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Taget method: " + methodName);
System.out.println("Taget method args: " + args);
}
/**
* 如果只想在连接点返回的时候记录日志,应使用返回通知代替后置通知。
* 在返回通知中,只要将 returning 属性添加到 @AfterReturning 注解中,就可以访问连接点的返回值
* 声明该方法是一个返回通知:在目标方法正常结束之后返回(目标方法执行出现异常时不再执行)
* 返回通知可以访问目标方法的执行结果
*
* @param joinPoint
* @param result
*/
@AfterReturning(value = "execution(* com.aspectJ.cutPoint.*.*(..))", returning = "result")
public void afterQueryReturning(JoinPoint joinPoint, Object result) {
System.out.println("我是返回通知的方法:");
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Taget method: " + methodName);
System.out.println("Taget method args: " + args);
System.out.println("Taget method execute result: " + result);
}
/**
* 声明该方法是一个异常通知:在目标方法出现异常时执行此方法
* 异常通知可以访问目标方法中的异常对象,且可以指定在出现特定异常时再执行通知代码
*/
@AfterThrowing(value = "pointCutMethod()", throwing = "e")
public void afterAllThrowing(JoinPoint joinPoint, Exception e) {
System.out.println("我是异常通知的方法:");
System.out.println("方法执行时抛出的异常" + e);
}
/**
* 声明该方法是一个后置通知:在目标方法开始之后执行(即使目标方法执行出现异常也会执行)
* 后置通知中不能访问目标方法的执行结果
*/
@After("pointCutMethod()")
public void doAfter() {
System.out.println("我是后置通知的方法:");
}
/**
* 环绕通知需要携带ProceedingJoinPoint类型的参数
* 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
* 且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
@Around("pointCutMethod()")
public Object around(ProceedingJoinPoint pj) {
String methodName = pj.getSignature().getName();
Object object = null;
try {
System.out.println(" 我是环绕方法执行之前的输出,我比前置方法执行的还早");
//执行目标方法
object = pj.proceed();
System.out.println("我是环绕方法我执行了");
} catch (Throwable e) {
//异常通知
System.out.println("The method: " + methodName + "异常通知: " + e.getMessage());
}
return object;
}
}
第三步:编写测试类
package com.aspectJ;
import com.aspectJ.cutPoint.MyCutPoint;
import com.dto.TradeCompany;
import com.service.ITradeCompanyService;
import com.service.impl.TradeCompanyServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.Schedules;
/**
* Created by tang on 2018/4/25.
*/
public class TestAspectAdvice {
@Test
public void testAnnotationBeforeAdvice() {
System.out.println("======================================");
ApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
ITradeCompanyService myCutPoint = (ITradeCompanyService) context.getBean("tradeCompanyServiceImpl");
myCutPoint.selectCompany(new TradeCompany(),1,10);
System.out.println("======================================");
}
}