SpringAOP面向切面的通知

一、通过接口实现通知效果

  配置applicationContext.xml文件,指定切面,在切面中接入各种通知

<!-- 配置扫描器   不同的包用逗号分隔 -->
    <context:component-scan base-package="aop">
    </context:component-scan>
<!-- 前置通知类 -->
    <bean id="logBefore" class="aop.LogBefore"></bean>
    <bean id="logAfter" class="aop.LogAfter"></bean>
    <bean id="logException" class="aop.LogException"></bean>
    <bean id="logAround" class="aop.LogAround"></bean>
    
    <aop:config>
        <!-- 配置切入点 execution中的内容可以与*(灵活替代各种路径和修饰符以及方法名)和..(指任意参数)任意搭配
         多个用execution(..) or execution(..)连接 -->
        <aop:pointcut expression="execution(public void service.impl.StudentSevImpl.addStudent(entity.Student))" id="myPoint"/>
        <!-- 将前置通知和切入点连接起来 -->
        <aop:advisor advice-ref="logBefore" pointcut-ref="myPoint"/>
        <aop:advisor advice-ref="logAfter" pointcut-ref="myPoint"/>
        <aop:advisor advice-ref="logException" pointcut-ref="myPoint"/>
        <aop:advisor advice-ref="logAround" pointcut-ref="myPoint"/>
    </aop:config>

  tip:aop中常用的几个expression表达式 “bean(要切入的bean标签id)”、"execution(public * *.*.*.*(args))"、"within(package+通配符)"。

  1.1、前置通知MethodBeforeAdvice接口

public class LogBefore implements MethodBeforeAdvice{
    
    //前置通知方法的实现
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置通知……");
    }

}

  1.2、后置通知AfterReturningAdvice接口

public class LogAfter implements AfterReturningAdvice{
    
    /**
     *  target:指调用插入点方法的对象
     *  method:切入点的方法
     *  args:切入点方法的参数
     *  returnValue:切入点方法的返回值
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",返回值:"+returnValue);
    }

}

  1.3、异常通知ThrowsAdvice接口

public class LogException implements ThrowsAdvice{
    /**
     *   void afterThrowing([Method, args, target], ThrowableSubclass)
     *   [Method, args, target]:这三个参数要么一起存在,要么都不要
     *   虽然是空接口,但必须实现该方法
     */
    public void afterThrowing(Method method,Object[] args,Object target, Throwable e) {
        System.out.println("异常通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",异常类型:"+e.getStackTrace());
    }
}

  1.4、环绕通知MethodInterceptor接口

public class LogAround implements MethodInterceptor{
    
    /**
     *  本质是通过拦截器实现
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object proceed = null;
        //方法体1:相当于前置通知
        System.out.println("环绕方法的前置通知...");
        try {
            proceed = invocation.proceed();      //放行方法,获取方法执行后的返回值
            Object target = invocation.getThis();
            Method method = invocation.getMethod();
            Object[] args = invocation.getArguments();
            //方法体2:相当于后置通知
            System.out.println("环绕方法的后置通知...对象:"+target+",方法:"+method.getName()+",参数:"+args[0]+",返回值:"+proceed);
        }catch(Exception e) {
            //方法体3:相当于异常通知
            System.out.println("环绕方法的异常通知...");
        }
        return proceed;
    }

}

二、通过注解来实现AOP通知

  在applicationContext.xml中开启注解:

<!-- 开启注解对aop的支持 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  @Component将改类放入IOC容器中,@Aspect声明为通知类

@Component("logAnnotation")
@Aspect
public class LogBeforeAnnotation {
    /**
     *  运用*和..定义方法的范围
     *  JoinPoint:获取执行方法各种参数的对象,类似环绕对象的invocation
     *  returningValue:在后置通知注解中,returning来设置返回值
     */
    @Before("execution(public void service.*.addStudent(..))")
    public void myBefore() {
        System.out.println("-------注解的前置通知---------");
    }
    
    
    @AfterReturning(pointcut="execution(public void service.*.addStudent(..))",returning="returnValue")
    public void myAfter(JoinPoint jp,Object returnValue) {
        Object[] args = jp.getArgs();
        Object target = jp.getTarget();
        //签名即方法的签名
        Signature signature = jp.getSignature();
        String methodName = signature.getName();
        System.out.println("-------注解的后置通知---------");
        System.out.println("执行方法的对象:"+target+",方法名:"+methodName+",参数:"+Arrays.toString(args)+",返回值:"+returnValue);
    }
    
    @AfterThrowing(pointcut="within(service.impl..*)",throwing="e")
    public void myException(JoinPoint jp,NullPointerException e) {
        System.out.println("-----注解异常通知:"+e.getStackTrace());
    }
    
}

三、通过Schema的方式配置

  在applicationContext.xml中开启schema

<bean id="logSchema" class="aop.LogSchema"></bean>

<aop:config>
        <!-- 配置切入点 execution中的内容可以与*(灵活替代各种路径和修饰符以及方法名)和..(指任意参数)任意搭配
         多个用execution(..) or execution(..)连接 -->
        <aop:pointcut expression="execution(public void service.impl.StudentSevImpl.addStudent(entity.Student))" id="myPoint"/>
                <!-- 通过Schema的方式配置通知 -->
        <aop:aspect ref="logSchema">
            <aop:before method="before" pointcut-ref="myPoint"/>
            <aop:after-returning method="afterReturning" pointcut-ref="myPoint" returning="returnValue"/>
            <aop:after-throwing method="whenException" throwing="e" pointcut-ref="myPoint"/>
            <aop:around method="myAround" pointcut-ref="myPoint"/>
        </aop:aspect>
</aop:config>

  用JoinPoint来代替 对象target, 方法method, 参数 args,如果是环绕通知则须用ProceedingJoinPoint来代替

public class LogSchema {
    
    public void afterReturning(JoinPoint jp,Object returnValue) throws Throwable {
        Object target = jp.getTarget();
        Signature method = jp.getSignature();
        Object[] args = jp.getArgs();
        System.out.println("Schema后置通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",返回值:"+returnValue);
    }
    
    public void before() throws Throwable {
        System.out.println("Schema前置通知……");
    }
    
    public void whenException(JoinPoint jp,NullPointerException e) {
        System.out.println("-----Schema异常通知:"+e.getStackTrace());
    }
    
    public Object myAround(ProceedingJoinPoint pJoinPoint) {
        Object returnVlaue = null;
        try {
            System.out.println("Schema方法的前置通知...");
            returnVlaue = pJoinPoint.proceed();
            Object target = pJoinPoint.getTarget();
            String name = pJoinPoint.getSignature().getName();
            Object[] args = pJoinPoint.getArgs();
            System.out.println("Schema方法的后置通知...对象:"+target+",方法:"+name+",参数:"+args[0]+",返回值:"+returnVlaue);
        }catch(Exception e) {
            System.out.println("Schema方法的异常通知...");
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return returnVlaue;
    }
}

猜你喜欢

转载自www.cnblogs.com/709539062rao/p/12636869.html