由于一直以来小项目做的多,造成了轻后端重前端的恶果,结果后端现在还在使用陈旧的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" class="ModuleB" scope="prototype"/> <bean id="DbOp" class="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" class="ModuleC" scope="prototype"/>
且代码更清晰易懂。