##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 -->
<bean id="theLogger" class="com.lsl.ssm.aop.ErrorLogger"/>
<!-- 切面配置 -->
<aop:config>
<!-- 定义切入点 (com.lsl.ssm.service)包下所有类所有方法,即这些方法发生异常都将会执行afterThrowing()方法-->
<aop:pointcut expression="execution(* com.lsl.ssm.service.*.*(..))" id="pointcut"/>
<!-- ref 引用包含增强方法的Bean -->
<aop:aspect ref="theLogger">
<!-- 将afterThrowing()方法定义为异常抛出增强并引用poincut切入点 -->
<!-- 通过throwing属性指定名为e的参数注入异常实例 -->
<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 -->
<bean id="theLogger" class="com.lsl.ssm.aop.AfterLogger"/>
<!-- 最终增强 切面配置 -->
<aop:config>
<!-- 定义切入点 (com.lsl.ssm.service.UserService)类所有方法,即UserService下的说有方法-->
<aop:pointcut expression="execution(* com.lsl.ssm.service.UserService.*(..))" id="pointcut"/>
<!-- 引用包含增强方法的Bean -->
<aop:aspect ref="theLogger">
<!-- 将afterThrowing()方法定义为异常抛出增强并引用poincut切入点 -->
<!-- 通过throwing属性指定名为e的参数注入异常实例 -->
<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 -->
<bean id="theLogger" class="com.lsl.ssm.aop.AroundLogger"/>
<!-- 切面配置 -->
<aop:config>
<!-- 定义切入点 (com.lsl.ssm.service)包下所有类所有方法-->
<aop:pointcut expression="execution(* com.lsl.ssm.service.*.*(..))" id="pointcut"/>
<!-- 引用包含增强方法的Bean -->
<aop:aspect ref="theLogger">
<!-- 将aroundLogger()方法定义为环绕增强并引用pointcut切入点 -->
<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、配置,使用注解方式,配置就简单多了!下面就是的全部配置了!
<!-- 自动扫描dao和service下的类,通过注解自动生成对应的Bean -->
<context:component-scan base-package="com.lsl.ssm.service,com.lsl.ssm.dao"/>
<bean class="com.lsl.ssm.aop.ErrorLogger"/>
<!-- 启用对于@AspectJ注解的支持 自动代理-->
<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、配置,使用注解方式,配置就简单多了!下面就是的全部配置了!
<!-- 自动扫描dao和service下的类,通过注解自动生成对应的Bean -->
<context:component-scan base-package="com.lsl.ssm.service,com.lsl.ssm.dao"/>
<bean class="com.lsl.ssm.aop.AroundLogger"/>
<!-- 启用对于@AspectJ注解的支持 自动代理-->
<aop:aspectj-autoproxy/>
小结:使用@AspectJ注解方式,可以看到配置简单了很多,上面展示的三种增强其实差别不大,无非就是注解名称和包名不同。可以注意下@Autowired和@Resource的用法。该方式的优点是:方便、简洁、有助于增强程序的内聚性。缺点就是:注解分散在各个class文件中,不利于后期维护。
更多推荐
MybatisHelperPro <<<<自己开发的一个Mybatis反编译插件,能快速生成代码,有兴趣可以看看
@Author 瞌睡虫
@mybatis-3.2.2
@Database: mysql 5.7.15
@Tool: MyEclipse