利用aop重构数据访问层
由于一直以来小项目做的多,造成了轻后端重前端的恶果,结果后端现在还在使用陈旧的jsp,数据访问层重复代码也不少,近来看了下 spring in action决定对这一部分进行一些修改
1。原先架构
每个模块一个类,层层继承,形成模块功能链
public class Module { public void actionA(){} public void actionC(){}.....}public class ModuleA extend Module{ public void actionA(){ Connection con=DB.getConnection(); try{ }catch(....){ logger.error(...); }finally{ con.close(); } } //other actions}public class ModuleB extends ModuleA{ public void actionB(){ } //other actions }?调用时,只需调用ModuleB的操作(继承最低层功能类,包含所有操作),
?
Module getModule() { return new ModuleB();}getModule().action..(...);??
一方面connection处理在各个方法冗余,另一方面那么当新增加模块时,有两个选择
1.三处源代码修改
public class Module { //added action}public class ModuleC extends ModuleB{ public void actionC(){ } //other actions }Module getModule() { return new ModuleC();}2.还是三处源代码修改
public class Module { //added action}public class ModuleB extends ModuleC{ public void actionB(){ } //other actions }public class ModuleC extends ModuleA{ public void actionC(){ } //other actions }即关键为维护链状继承结构。
2.利用aop重构
利用spring的aop特性将connection创建过程抽离出来,利用aop前置将connection先创建出来保存在模块中,后置销毁成员变量connection。
?
1.首先修改基类,将连接做为成员变量:
public class Module { private Connection con; public void setConnection(Connection con){this.con=con;} public Connection getConnection(){return this.con;} public void actionA(){} // .. other actions}?
其他模块数据库操作改变
?
public class ModuleA extends Module{ public void actionA(){ Connection con=this.getConnection(); //.. 数据库操作 //不用关闭,不用处理异常 } //other action}在各个模块的操作中,不用关闭连接,也不用处理异常,将这些功能切面独立出来
2.创建 aspect
?
2.1 xml配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><bean id="Op" scope="prototype"/><bean id="DbOp" /><aop:config><aop:aspect ref="DbOp"><aop:pointcut id="DbOpPointcut"expression="execution(* Module*.action*(..)) and target(bean)" /><aop:before method="prepareConnection" pointcut-ref="DbOpPointcut"arg-names="bean" /><aop:after-returning method="closeConnection"pointcut-ref="DbOpPointcut" arg-names="bean" /><aop:after-throwing method="exceptionHandle"pointcut-ref="DbOpPointcut" arg-names="bean" /></aop:aspect></aop:config></beans>
其中Op指向继承最低层的模块对象(包含所有模块操作),对 Module*类的action*方法创建pointcut,并且给advise传递target参数,即module功能对象。
2.2 aspect
public class DbOp {static Logger logger = Logger.getLogger(DbOp.class);public void prepareConnection(Module impl) throws SQLException {Connection con = null;con =DB.getConnection();impl.setConnection(con);logger.info("prepareConnection");}public void closeConnection(Module impl) throws SQLException {Connection con = impl.getConnection();con.close();con = null;impl.setConnection(con);logger.info("closeConnection");}public void exceptionHandle(Module impl) {Connection con = impl.getConnection();if (con != null) {try {con.close();} catch (SQLException e) {e.printStackTrace();}con = null;impl.setConnection(con);}logger.info("exceptionHandle");}}?将创建连接,销毁连接,异常处理分离开,并将连接保存到模块功能对象即可。
3.最后改变获取模块功能对象的方式
?
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");Module getModule(){ return (Module)ctx.get("Op");}?这样的话以后添加新的模块,只需更改两处源码:
?
public class Module { //added action}public class ModuleC extends ModuleB{ public void actionB(){ } //other actions }?
以及一处xml配置即可:
?
<bean id="Op" scope="prototype"/>
且代码更清晰易懂。
?
?
1 楼 hanqunfeng 2010-02-27 既然用了spring,为什么不直接使用数据库模板类来处理dao层。