SSM框架之Spring-AOP常见增强处理的使用

SSM 框架学习 (Spring篇)

一、常见增强类型与特点
增强类型 注解 特点
前置增强 @Before 目标方法前织入增强方法。
后置增强 @AfterReturning 目标方法正常执行后织入增强方法(不出现异常)。
异常增强 @AfterThrowing 目标方法发生异常后织入的增强方法,可拔插的异常处理方案。
最终增强 @After 无论目标方法是否发生异常,都会在目标方法执行完成后织入增强方法,类似异常处理机制中的finally,常用于释放资源。
环绕增强 @Around 在目标方法的前后都可以织入增强方法,环绕增强是功能最强大的增强处理,可获取或修改目标方法的参数、返回值,可对它进行异常处理。

因之前介绍AOP的文章已经有了 前置增强与后置增强 的用法介绍,可以看我之前的文章:SSM框架之Spring-AOP的理解与基本使用,相比较而言也是最简单的,下面的介绍也是在SSM框架之Spring-AOP的理解与基本使用项目的基础上进行修改!所以这里就不赘述了,如何搭建Spring框架也是。

由于怕篇幅过长,这里只贴主要代码。下面将介绍两种实现增强的方法–1、文件配置法 2、@AspectJ注解法

二、文件配置法(异常增强)
1、先定义好异常增强切入方法
public class ErrorLogger {
    private static final Logger log = Logger.getLogger(ErrorLogger.class);
    // 当切入方法发生异常时,该方法会执行
    public void afterThrowing(JoinPoint jp, Exception e) {
        log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
    }
}
2、增强方法的配置,该有的解释已经在注解里了,注意包名!

<bean id="theLogger" class="com.lsl.ssm.aop.ErrorLogger"/>

<aop:config>
    
    <aop:pointcut expression="execution(* com.lsl.ssm.service.*.*(..))" id="pointcut"/>
    
    <aop:aspect ref="theLogger">
        
        
        <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
    aop:aspect>
aop:config>
三、文件配置法(最终增强)
1、先定义好最终增强切入方法
public class AfterLogger {
    private static final Logger log = Logger.getLogger(AfterLogger.class);
    // 方法结束执行! 无论是否发生异常都会得到执行,类似finally块的作用!
    public void afterLogger(JoinPoint jp) {
        log.info(jp.getSignature().getName() + " 方法结束执行!(最终增强:无论是否发生异常都会得到执行,类似finally块的作用!)");
    }
}
2、增强方法的配置!

<bean id="theLogger" class="com.lsl.ssm.aop.AfterLogger"/>

<aop:config>
    
    <aop:pointcut expression="execution(* com.lsl.ssm.service.UserService.*(..))" id="pointcut"/>
    
    <aop:aspect ref="theLogger">
        
        
        <aop:after method="afterLogger" pointcut-ref="pointcut"/>
    aop:aspect>
aop:config>
四、文件配置法(环绕增强)
1、先定义好环绕增强切入方法
public class AroundLogger {
    private static final Logger log = Logger.getLogger(AroundLogger.class);

    public Object aroundLogger(ProceedingJoinPoint pjp) throws Throwable {
        log.info("调用 " + pjp.getTarget() + " 的 " + pjp.getSignature().getName()
                + " 方法,方法入参:" + Arrays.toString(pjp.getArgs()) + " (目标执行前执行!)");
        // 目标执行前执行 = 前置增强
        try {
            // 目标执行后执行 = 后置增强
            Object result = pjp.proceed();
            log.info("调用 " + pjp.getTarget() + " 的 "
                    + pjp.getSignature().getName() + " 方法,方法返回值:" + result + " (目标不出现异常时执行!)");
            return result;
        } catch (Throwable e) {
            // 目标出现异常时执行 = 异常增强
            log.error(pjp.getSignature().getName() + " 方法异常: " + e + " (目标异常时执行!)");
            throw e;
        } finally {
            // 目标无论有没有发生异常都会执行 = 最终增强
            log.info(pjp.getSignature().getName() + " 方法执行结束! (任何时候都执行!)");
        }

    }
}
2、增强方法的配置!

<bean id="theLogger" class="com.lsl.ssm.aop.AroundLogger"/>

<aop:config>
    
    <aop:pointcut expression="execution(* com.lsl.ssm.service.*.*(..))" id="pointcut"/>
    
    <aop:aspect ref="theLogger">
        
        <aop:around method="aroundLogger" pointcut-ref="pointcut"/>
    aop:aspect>
aop:config>

小结:可以看到,使用配置文件切入增强方法是不需要修改原程序代码的!只需新建好增强方法的类再配置好切入的位置即可,配置比较集中,方便后面修改与管理。而缺点也比较明显,就是配置比较繁琐,类型不安全,配置文件过多时难以管理等。

注意:使用@AspectJ注解方式,JDK要求在5.0以上

五、@AspectJ注解法(异常增强)
1、同样的,先定义好环绕增强切入方法,注意:不同于上面,这里多了两个注解@Aspect 和 @AfterThrowing
@Aspect // 用于标注AOP类
public class ErrorLogger {
    private static final Logger log = Logger.getLogger(ErrorLogger.class);

    @AfterThrowing(pointcut = "execution(* com.lsl.ssm.service.*.*(..))", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) {
        log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
    }
}
2、这里就需要在原有Dao层和业务层的实现类添加注释了
/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository //用于标注DAO类
public class UserDaoImp implements UserDao {...}

/**
 * 用户业务类,实现对User功能业务的管理
 */
@Service("service") // 用于标注业务类,这里指定bean的名称为”service“
public class UserServiceImp implements UserService {

    //声明接口类型的引用,和具体实现类解耦合
    @Autowired // 自动装配Bean
    private UserDao dao;
    ...
}
3、配置,使用注解方式,配置就简单多了!下面就是的全部配置了!

<context:component-scan base-package="com.lsl.ssm.service,com.lsl.ssm.dao"/>
<bean class="com.lsl.ssm.aop.ErrorLogger"/>

<aop:aspectj-autoproxy/>
六、@AspectJ注解法(环绕增强)
1、同样的,先定义好环绕增强切入方法,注意:不同于上面,这里多了两个注解@Aspect 和 @Around
@Aspect
public class AroundLogger {
    private static final Logger log = Logger.getLogger(AroundLogger.class);

    @Around("execution(* com.lsl.ssm.service.*.*(..))")
    public Object aroundLogger(ProceedingJoinPoint pjp) throws Throwable {
        log.info("调用 " + pjp.getTarget() + " 的 " + pjp.getSignature().getName()
                + " 方法,方法入参:" + Arrays.toString(pjp.getArgs()) + " (目标执行前执行!)");
        // 目标执行前执行 = 前置增强
        try {
            // 目标执行后执行 = 后置增强
            Object result = pjp.proceed();
            log.info("调用 " + pjp.getTarget() + " 的 "
                    + pjp.getSignature().getName() + " 方法,方法返回值:" + result + " (目标不出现异常时执行!)");
            return result;
        } catch (Throwable e) {
            // 目标出现异常时执行 = 异常增强
            log.error(pjp.getSignature().getName() + " 方法异常: " + e + " (目标异常时执行!)");
            throw e;
        } finally {
            // 目标无论有没有发生异常都会执行 = 最终增强
            log.info(pjp.getSignature().getName() + " 方法执行结束! (任何时候都执行!)");
        }

    }
}
2、这里就需要在原有Dao层和业务层的实现类添加注释了
/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository("userDao") //用于标注DAO类,这里指定bean名称为”userDao“
public class UserDaoImp implements UserDao {...}

/**
 * 用户业务类,实现对User功能业务的管理
 */
@Service("service") // 用于标注业务类,这里制定bean的名称为”service“
public class UserServiceImp implements UserService {

    //声明接口类型的引用,和具体实现类解耦合
//  @Autowired // 自动装配Bean
    @Resource(name="userDao") //为dao属性注入名为userDao的Bean
    private UserDao dao;
    ...
}
3、配置,使用注解方式,配置就简单多了!下面就是的全部配置了!

<context:component-scan base-package="com.lsl.ssm.service,com.lsl.ssm.dao"/>
<bean class="com.lsl.ssm.aop.AroundLogger"/>

<aop:aspectj-autoproxy/>

小结:使用@AspectJ注解方式,可以看到配置简单了很多,上面展示的三种增强其实差别不大,无非就是注解名称和包名不同。可以注意下@Autowired和@Resource的用法。该方式的优点是:方便、简洁、有助于增强程序的内聚性。缺点就是:注解分散在各个class文件中,不利于后期维护。

@Author 瞌睡虫
@mybatis-3.2.2
@Database: mysql 5.7.15
@Tool: MyEclipse

你可能感兴趣的:(java,SSM框架学习)