一、 注解实现
@Aspect 把当前类标识为一个切面
@Pointcut Pointcut是织入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around 环绕增强,目标方法执行前后分别执行一些代码
@AfterReturning 返回增强,目标方法正常执行完毕时执行
@Before 前置增强,目标方法执行之前执行
@AfterThrowing 异常抛出增强,目标方法发生异常的时候执行
@After 后置增强,不管是抛出异常或者正常退出都会执行
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.example.demo.Aspect.TestController.doNormal(..))")
public void pointCut(){}
@Before(value = "pointCut()")
public void before(JoinPoint joinPoint){
System.out.println("before通知执行结束");
}
/**
* 后置返回
* 如果第一个参数为JoinPoint,则第二个参数为返回值的信息
* 如果第一个参数不为JoinPoint,则第一个参数为returning中对应的参数
* returning:只有目标方法返回值与通知方法参数类型匹配时才能执行后置返回通知,否则不执行,
* 参数为Object类型将匹配任何目标返回值
*/
@AfterReturning(value = "pointCut()",returning = "result")
public void doAfterReturningAdvice1(JoinPoint joinPoint,Object result){
System.out.println("第一个后置返回通知的返回值:"+result);
}
@AfterReturning(value = "pointCut()",returning = "result",argNames = "result")
public void doAfterReturningAdvice2(String result){
System.out.println("第二个后置返回通知的返回值:"+result);
}
/**
* 后置异常通知
* 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
* throwing:只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行异常通知,否则不执行,
* 对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
*/
@AfterThrowing(value = "pointCut()",throwing = "exception")
public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
System.out.println(joinPoint.getSignature().getName());
if(exception instanceof NullPointerException){
System.out.println("发生了空指针异常!!!!!");
}
}
@After(value = "pointCut()")
public void doAfterAdvice(JoinPoint joinPoint){
System.out.println("后置通知执行了!");
}
/**
* 环绕通知:
* 注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用
* 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
*/
@Around(value = "pointCut()")
public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("@Around环绕通知:"+proceedingJoinPoint.getSignature().toString());
Object obj = null;
try {
obj = proceedingJoinPoint.proceed(); //可以加参数
System.out.println(obj.toString());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("@Around环绕通知执行结束");
return obj;
}
}
二、xml 配置
<!--注册bean-->
<!-- 实体类-->
<bean id="userService" class="service.UserServiceImpl"/>
<!-- 增强类-->
<bean id="coutomAOP" class="com.CoutomAOP"/>
<aop:config>
<!--这里的ref指定被 切入 的类是哪一个-->
<aop:aspect ref="coutomAOP">
<!--切入点-->
<aop:pointcut id="cut" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--切入点之前执行,这里的方法名即是我们自定义类中的方法名-->
<aop:before method="before" pointcut-ref="cut"/>
<!--切入点之后执行,这里的方法名即是我们自定义类中的方法名-->
<aop:before method="after" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
public class CoutomAOP{
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
三、 api 实现
public class AopBefore implements MethodBeforeAdvice {
/**
* method : 要执行的目标对象的方法
* args : 被调用的方法的参数
* target : 目标对象
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("方法执行前执行。。。。。。。");
}
}
public class AopAfter implements AfterReturningAdvice {
/**
* method : 要执行的目标对象的方法
* args : 被调用的方法的参数
* result : 返回值
* target : 被调用的目标对象
*/
@Override
public void afterReturning(Object result, Method method, Object[] args, Object target){
System.out.println("方法执行后执行。。。。。。。");
}
}
<!--注册bean-->
<bean id="userService" class="service.UserServiceImpl"/>
<bean id="aopAfter" class="AopAfter"/>
<bean id="aopBefore" class="AopBefore"/>
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="cut" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="aopAfter" pointcut-ref="cut"/>
<aop:advisor advice-ref="aopBefore" pointcut-ref="cut"/>
</aop:config>