您的位置:首页 > 其它

切面和自定义注解的配合使用

2016-12-04 00:41 537 查看

一.概述

基于切面的编程(AOP)也许大家并不陌生,大家经常使用切面编程来解决事务问题。但是切面也有弊端,以笔者的经验看来,使用切面的不方便之处在于切面的精确度问题,我们很难把事务加到大量的指定类的指定方法上,本文就通过Spring AOP和自定义注解的配合使用来解决该问题。

二.Spring AOP切面的使用和问题

使用:

以事务为例,我们在搭建J2EE项目框架时,势必要处理事务。通常我们的做法是给service层的DML操作方法增加事务,具体代码如下:

// 对数据源进行管理
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*"     propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="save*"    propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="insert*"  propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="update*"  propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="modify*"  propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="delete*"  propagation="REQUIRED"  rollback-for="Exception" />
<tx:method name="remove*"  propagation="REQUIRED"  rollback-for="Exception" />
</tx:attributes>
</tx:advice>

<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(* com.etc..service.impl.*ServiceImpl.*(..))" advice-ref="txAdvice" />
</aop:config>


通过上面的配置,可以实现事务的处理,但是这个配置却非常不灵活,他限制了类必须在service层,其次,方法名必须以add、save、insert等开头,才能被切面管理到,如果不符合这些规则改怎么办呢?

新的需求:

在曾经的开发中遇到这样一个需求,系统中的部分业务方法在被调用到时,需要向log表插入日志,业务方法名没有规律,你不可能把所有的业务方法名都配置到上面,那么问题就来了,是否有一种语法可以在每个需要记录日志的方法中进行标识,让Spring AOP感知到,这就是下面要讲解的–自定义注解。

三.自定义注解

Annotation(注解)是JDK1.5以后引入的新特性,它是以‘@注解名’的形式在代码中存在的,它可以出现在类、方法和属性的上方,一旦被标记了注解,那么在编译期或运行期就可以动态的获取哪些类、哪些方法或属性被标记了注解,从而针对这些类、属性和方法进行对应的处理,正式因为这个特性,才可以解决我们上面提到的问题。

如何自定义注解:

在了解自定义注解钱,需要了解元注解。元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:

@Target

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

@Retention

@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。例如我们常见的@Override注解,他的@Retention就在source阶段,因为他仅仅是针对方法覆盖进行语法检查,只要符合了规则即可,在运行阶段就不需要了。

@Documented

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如
4000
果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

四.具体实现

注解代码:

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogOperation {

}


在代码中,我们定义了,改注解是方法级别,并且是在运行阶段有效的。


切面代码:

@Aspect
@Component
public class LogOperationAspect {

Logger log = LoggerFactory.getLogger(LogOperationAspect.class);

@Autowired
ILogOperationService logOperationService;

// 这里是关键点,把切面的连接点放在了我们的注解上
@Pointcut("@annotation(com.etc.annotation.LogOperation)")
public void controllerAspect() {
}

// 在这里定义前置切面
@Before("controllerAspect()")
public void beforeMethod(JoinPoint joinPoint) {
// 这里执行保存日志的动作
this.saveLogOperation(joinPoint, StatusEnum.SUCCESS);
}
}


使用切面的代码:

// 只需要增加这样一个注解,就可以被切面管理
@LogOperation
@ResponseBody
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public Map<String, Object> getDemo(@PathVariable Integer id, HttpServletRequest request,
HttpServletResponse response) {
DemoVO vo = this.demoService.selectById(id);
return ResultMapper.convertSuccess(vo);
}


五.总结

通过上面代码,我们可以看到,只要我们在期望记录日志的方法上增加@LogOperation注解,该方法的动作就会被记录进日志表,不管方法叫什么名字,类在什么位置,都可以轻松的解决,而且没有代码入侵,期望本篇博客对大家有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  自定义注解 切面