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 -->
<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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值