java项目开发实践经验之三:spring的那些事儿

相信spring现在已经成为j2ee开发的首选框架,也深受广大java开发者的喜爱,它的ioc、aop以及各种扩展应用都使开发者受益。它不仅是一个开发框架,同时还把很多优秀的设计理念潜移默化的传递给了使用者...好了,具体spring有多优秀不是这篇文章的重点,以下就谈一下笔者在项目中使用spring的实际经验吧。

1 项目的哪些地方需要用到spring
这应该是一个相当大的话题,不过还是有必要阐述一下。就当前典型的j2ee应用或web应用上流行的mvc(如ssh)框架而言,spring应用在以下几个方面
核心开发框架:spring作为核心容器,通过主要组件BeanFactory并使用ioc实现对所有bean的管理。在实际应用中,首先要秉承接口模式的编程思路,定义应用类之前先定义接口,然后再定义实现类,而调用的时候则调用接口而不是实现类。同时需要配置一个或多个spring的xml配置文件,把调用接口映射到实现类。
dao端的框架支持:在三层框架模式下(web,service,dao),通过HibernateTemplate和JdbcTemplate等支持类,在dao层对jdbc以及Hibernate等主流的ORM数据库调用模式进行支持。一般都有专门的jdbc以及hibernate的配置文件对DAO层使用的bean进行设置。
service端的框架支持:在serivce层通过ioc进行bean的管理配置,同时进行事务控制的定义。
aop:利用拦截器配置管理特性
jndi:利用spring的context组件对jndi进行定义,通常用于数据库连接池的配置和查找
其他:spring1.2版本的mvc组件是针对web端的应用框架,尽管理念非常oop,不过实际使用的时候确实不如struts2好使,spring 2.0以后的mvc据说有很大改进,以后有机会再用吧。另外spring的定时任务(job)也经常用到,后边会有提及。

2 spring的orm组件的使用经验
ssh框架的一个典型应用,通过HibernateTemplate实现spring与hibernate的集成。一般都是通过在配置文件向继承HibernateDaoSupport的dao实现类注入sessionFactory,这个sessionFactory实现类一般被定义为LocalSessionFactoryBean,而LocalSessionFactoryBean这个类也属于spring的hibernate支持包,它的一个重要属性是dataSource,对应的是jdbc的DataSource接口,而这个dataSource又可以通过ioc的方式注入实际的实现类,这个类既可以是各种java连接池的DataSource实现类,也可以是JndiObjectFactoryBean--spring用于进行数据源查找的jndi实现类。综上所述,正式由于这一连串的联系,实现了hibernate模式下的数据库接入。而jdbc模式也是如此联系,不同的是spring使用JdbcTemplate类进行支持。在使用中一些细节需要注意,比如
如何实现批量更新:HibernateTemplate的bulkUpdate方法可以用hql语句直接进行批量更新
对结果列表进行加工:不论通过jdbc还是hibernate方式,如果需要对find方法取得的列表中的对象进行加工,显然使用回调模式进行效率更高。实际上如果使用HibernateTemplate并且希望查询出的结果不是对象列表而是数组列表,那么也可以使用回调,如下:
String hql = "select t.id,t.name from test t";
List list = (List) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws SQLException, HibernateException {
SQLQuery query = session.createSQLQuery(sql);
List children = query.list();
return children;
}
});
Iterator it = list.iterator();
while(it.hasNext()){
Object[] obj = (Object[])it.next();
System.out.println("id:" + obj[0]);
//do some business here
}
如上述代码所示,某些时候我们希望直接使用字段来进行逻辑处理,那么HibernateTemplate的find方法显然是不合适的,而回调模式返回的list中的内容是对象数组
调用存储过程:HibernateTemplate可以通过回调调用存储过程
hibernateTemplate.execute(new HibernateCallback(){
public Object doInHibernate(Session session) throws SQLException{
CallableStatement cs = session.connection().prepareCall("{call usr.someProc}");
cs.executeUpdate();
return null;
}
}
);

3 spring的事务控制
在项目中,一般使用spring的声明式方法控制数据库事务,定义数据库事务只需要通过配置文件中配置即可,这种模式的技术基础是基于AOP的。
事务配置定义:在三层构架中,通常都在service层进行业务逻辑处理,以及事务控制。因此spring在service层可以单独定义一个配置文件,映射service层中使用的bean,并且在定义这个bean的配置同时进行事务声明,有多种方式。最直接的方式是定义这个bean的实现类为TransactionProxyFactoryBean--spring的事务控制代理,这种事务配置可以参见下面的代码例子:
<bean id="someBusinessBean"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref bean="someBusinessBeanImpl"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
在上面的代码中定义了someBusinessBean这个bean,其中target属性中定义实际的业务接口实现类。并且在transactionAttributes属性中针对method进行事务声明,最常用的声明是PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。另外可以定义只读事务readOnly,用于只读的数据库操作。同时我们还注意到事务定义中包含了异常情况的配置:如果出现MyCheckedException这个自定义异常,则数据库进行回滚。
还有一种方式是继承式事务定义,例子如下:
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="update*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="someBusinessBean" parent="txProxyTemplate">
<property name="target">
<bean class="com.myBusi.someBusinessBeanImpl">
<property name="dao" ref="dao"/>
</bean>
</property>
</bean>
可以看出,这种方式先使用一个父类作为事务控制的统一定义,然后具体的业务bean通过继承来实现事务的配置。其实这2中配置方式并没有本质的区别,只是第二种定义起来会省事一点。
另外在实际项目中有一个发现,在websphere6.0的容器下部署的web应用,使用websphere自带的数据库连接池,当spring事务配置为readOnly,在数据量比较大,并且有一定并发量时会导致websphere连接池抛出异常,并导致性能严重下降。去掉readOnly选项就恢复正常了,这种情况不容易在测试环境重现,因此只能去掉readOnly选项,发现去掉以后性能也没有太多的下降。
另外如果一些特殊的场景直接在代码中进行事务提交(比如大批量插入数据),则需要用到spring的编程事务,PlatformTransactionManager这个类是spring针对编程式事务的支持类。

4 spring与数据库连接池
在spring中可以很方便的配置数据库连接池,一种是直接配置连接池,以proxool连接池为例,配置代码如下:
<bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
<property name="alias"><value>mydb</value></property>
<property name="user"><value>test</value></property>
<property name="password"><value>test</value></property>
<property name="driver"><value>com.mysql.jdbc.Driver</value></property>
<property name="driverUrl"><value>jdbcUrl</value></property>
<property name="minimumConnectionCount"><value>10</value></property>
<property name="maximumConnectionCount"><value>20</value></property>
<property name="prototypeCount"><value>1</value></property>
<property name="houseKeepingSleepTime"><value>90000</value></property>
</bean>
如上,在配置文件中定义了dataSource这个bean,映射到ProxoolDataSource这个proxool的数据库数据源的实现类,在属性里的配置就是连接池的一些基本参数
我想更常用的还是使用jndi作为数据源,配置代码如下:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>jdbc/mydblink</value></property>
</bean>
在上面的代码中使用JndiObjectFactoryBean作为数据源,而这个数据源实际负责实现jndi的查找,在容器中查找到jndiName属性定义的名称所对应的实际的数据源,来提供给应用进行调用。实际的数据源则是在tomcat、weblogic、websphere等中间件容器中定义的。

5 其他的spring心得
直接获得bean:有很多时候,我们不希望频繁的修改配置文件以及增加set方法来得到spring容器定义的bean,那么可以使用ApplicationContext的getBean方法来直接获取bean的实例。
job定义:spring支持定时计划任务,一种是一次性触发,更有用的一种的定时轮询,写法例子如下:
"0 0/5 14-18 * * ?" 在每天下午2点下午6点期间的每5分钟触发
OpenSessionInView:spring为了支持在页面中延迟加载事务的一个filter,建议谨慎使用,容易对数据库连接性能造成瓶颈

总结:以上列举了一些项目中使用spring的地方,相信还有更多的没有列举出来,在以后的文章里再补充吧

[b][i]广告时间[/i][/b]: 轻松阅读,尽在[url=http://www.article-reading.com]阅读地带[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值