Spring框架aop实现

1 前言

Spring框架两大核心技术为IOC和AOP,今天就来讲解AOP的具体使用,AOP为Aspect Oriented Programming的缩写,被称为面向切面编程。AOP主要用于处理共同逻辑,例如日志记录、方法执行性能统计、事务控制等等。AOP的相关概念有:方面、目标、切入点、通知。

2 相关概念

2.1 方面

指封装共通处理的组件,该组件被作用到其他目标组件方法上,通俗的讲就是一个普通的JavaBean。

2.2 目标

是指被一个或多个切面所作用的对象,也即动态代理中的目标对象。

2.3 切入点

用于指定哪些方法使用方面功能,也即被作用的对象里的实际方法。

2.4 通知

用于指定作用的时机,即方法执行前后还是返回值后执行。通知主要有:before、after、after-throwing、after-returning、around五类。

3 具体使用

Spring框架中主要用两种方式实现AOP:基于XML配置、基于注解方式。

3.1 基于XML配置

AOP实现依赖spring-aop相关jar,所以需引入相关jar包,并引入aop命名空间,如图
这里写图片描述
①定义方面

<!-- 定义一个方面Bean,用于记录日志信息  -->
<bean id="myAspect" class="com.pengmm.aop.MyAspect"/>
具体的com.pengmm.aop.MyAspect代码如下
package com.pengmm.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 方面:记录日志信息<p>
 * 任何advice方法第一个参数都可以为:JoinPoint joinPoint 封装了参数信息;<p>
 * around advice 第一个参数为:ProceedingJoinPoint,它是JoinPoint的子类,封装了参数和返回值信息
 * @author pengmm
 */
public class MyAspect {
    /**
     * 前置通知
     * 
     * @param joinPoint
     *            封装参数信息
     * @return
     */
    public void mybefore(JoinPoint joinPoint) {
        System.out.println("========我是一个前置通知========");
    }

    /**
     * 无论正确返回与否,都将执行,通常用于关闭或释放资源<p>
     * &lt;aop:after method="myafter" pointcut-ref="myPointcut" />
     */
    public void myafter() {
        System.out.println("========我是一个后置通知========");
    }

    /**
     * 环绕通知<br>
     * &lt;aop:around method="myaround" pointcut-ref="myPointcut" />
     * 
     * @param joinPoint
     *            封装参数和返回值
     */
    public void myaround(ProceedingJoinPoint joinPoint) {
        Logger logger = Logger.getLogger(MyAspect.class);
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        logger.debug("------->方法[" + className + "." + methodName + "]执行时间为:" + (endTime - startTime) + "ms");
    }

    /**
     * 后置返回值后通知,retval必须与xml声明的returning值相同<br>
     * <code>
     *  &lt;aop:after-returning method="myafterReturning" 
     *  pointcut-ref="myPointcut" returning="retVal" />
     * </code>
     * 
     * @param retVal
     *            返回值,指定类型Object表示可以返回任何类型
     */
    public void myafterReturning(JoinPoint joinPoint,Object retVal) {
    }

    /**
     * 当返回异常时通知<br/>
     * <code>
     * &lt;aop:after-throwing method="myafterThrowing" 
                pointcut-ref="myPointcut" throwing="exception"/>
        </code> <br/>
        Exception:指定异常的类型,比如指定IllegalArgumentException,则只有发生参数异常时才能执行通知
     * 
     * @param exception
     *            异常信息,此变量必须同throwing定义的值
     */
    public void myafterThrowing(Exception exception) {
        System.out.println(exception.getMessage());
    }
}

②每个aop配置都定义在<aop:config>标签下

<aop:config>
        <!-- 定义方面,可直接引用上面定义的方面  -->
        <aop:aspect ref="myAspect">
            <!-- 定义切入点,即设置作用于哪些类中的哪些方法  -->
            <aop:pointcut id="myPointcut" 
                expression="execution(* com.pengmm.service.*Impl.*(..)) and args(..)" />
            <!-- 定义各种通知 -->
            <aop:before method="mybefore" pointcut-ref="myPointcut" />
            <aop:after method="myafter" pointcut-ref="myPointcut" /> 
            <aop:after-throwing method="myafterThrowing" 
                pointcut-ref="myPointcut" throwing="exception"/>
            <aop:after-returning method="myafterReturning" 
                pointcut-ref="myPointcut" returning="retVal" />
            <aop:around method="myaround" pointcut-ref="myPointcut" />
        </aop:aspect>
    </aop:config>

③测试,定义了环绕通知,输出了自定义的通知内容。
这里写图片描述

3.2 基于注解方法

①开启自动代理注解

<!-- 开启aop自动代理注解  -->
<aop:aspectj-autoproxy />

②编写一个普通的类,通过注解声明

package com.pengmm.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * @Aspect 注册该类为一个方面Bean
 * @Component 把该Bean交给IOC容器管理,也可基于XML注入该Bean
 */
@Aspect
@Component
public class MyAnnotationAspect {
    /**
     * @Around定义一个环绕通知
     * 配置切入点:execution(* com.pengmm.service.*Impl.*(..)) and args(..)
     * @param joinPoint 封装方法参数和返回值信息
     */
    @Around("execution(* com.pengmm.service.*Impl.*(..)) and args(..)")
    public void myaround(ProceedingJoinPoint joinPoint) {
        Logger logger = Logger.getLogger(MyAspect.class);
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        logger.debug("------->方法[" + className + "." + methodName + "]执行时间为:" + (endTime - startTime) + "ms");
    }
}

③测试,执行结果同“基于XML配置”测试结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值