在铁科院做了一个关于医保报销的项目,在这个个系统中大量使用了下拉列表框,系统主要是给机关单位使用而且都是一些干部退休了啥的,年龄都比较大不愿意自己输入东西,因此界面上的很多值都是下拉列表框从数据字典表里面加载出来。
如此以来字典表的数据量变的越来越大,在一个界面上往往需要频繁的与字典表交互,觉的很影响性能于是我们增加了缓存,即为service层中的指定方法缓存功能,具体实现是利用Spring AOP+EHcache来做。
第一次执行某个方法的时候会去数据库里面查询,当第二次执行该方法时就会去从缓存里面查找,如有找到直接取值,找不到再去数据库里面查询。除此之外呢,我们还自定了tag标签,在界面上我们只需要引用一个写好的tag标签即可将一个下拉列表框加载到页面上,这样做也提高了下拉列表框的通用性,无论是前台还是后台将显示下拉列表的功能都抽象了出来,放到了一起,有益于代码的简洁和维护。
让我们看看是怎么样一步一步来实现这个功能的,涉及到了一些知识点有spring aop、encache缓存、自定义标签tag、tld文件等。
第一步:AOP为service层指定方法增加拦截,这里我拦截的是查询字典表的方法。
两种思路一种通过注解方式拦截,另一种通过配置文件方式但是我更倾向于使用配置文件,因为它灵活容易修改而且不需要改动代码,我把两种方式都试了一遍达到的效果是一样的。
配置文件如下;
1.通过配置文件<aop:config>来配置拦截
上面的两种写法是等价的,第一种将切点集合直接放到了<aop:after>里面,其实pointcut是<aop:after>标签的一个属性,下面的写法是把切点拿出来了,建议写第二种因为这种写好好理解,在写代码过程中易于阅读和方便理解也需要考虑。
2.通过注解实现切入的类:切面类
在配置文件中需要开启切面注解如下
在切入的时候,遇到了一个错误查找额很多资料发现参数是固定好了的,不可以随意更改,只可以传入JoinPoint和ProceedingJoinPoint这两个接口作为参数或者不传入参数,如果是其他的方法将报找不到切入点的错误。
第二步:为拦截的方法增加缓存ehcache,拦截的方法会执行下面的方法,转到缓存类的处理中并将调用对象上下文内容传入到缓存处理中。
在处理被拦截的方法之前会先处理这个方法,然后调用缓存类CacheHander将查询出来的结果添加到缓存中,当第二次再调用这个方法的时候就会从缓存中取出数据,缓存中没有的话再从数据库里面查询。
利用AOP切入的关键是把切入前调用方法的上下文传入到切面类里面,比如调用该方法的对象、方法名、以及方法里面的执行参数等等,当我们缓存一个方法的查询结果的时候,需要给该结果指定一个唯一键值,方便我们从缓存中取出数据,这个键值相对于缓存的方法是唯一的,常常拿类的全名、方法名、传入的实参列表,三个参数当做缓存对象的key值。通过这种切入式编程可以动态给程序增加新的功能,而不用动以前的代码,是一种不错的编程模式。
总结:
可以说AOP是面向对象编程OOP的补充和完善,OOP类设计好了之后结构是静态的、封闭的,任何需求的变化都可能对开发进度造成重要影响,试想一下OOP中引入了继承、封装、多太等特性来建立一种对象间的层次结构,在开发一个系统中对象会非常多,如果想为某些对象增加特殊功能则OOP无能为力,也可以增加进去但是一个一个增加很费事,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。
例如日志功能,日志代码往往水平地散步在所有对象层次中,而与需要添加日志的类的核心功能毫无关系,再比如权限、事务等如果不实用AOP每一个方法都需要开启事务,在OOP中会导致大量重复性的代码,而不利用各个模块的重用。
而AOP技术则恰恰相反,它利用了一种称为“横切”的技术,将多个类公共行为封装到了一个可重用的模块内部,并将其命名为“ASpect”,即方面。
上面利用AOP为查询字典的方法增加了缓存功能是AOP技术的一种典型应用,它可以同其他一些技术结合实现为系统实现更多的新功能。