spring的那些事儿

来源:百度文库 编辑:神马文学网 时间:2024/04/27 14:22:38
相信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的事务控制代理,这种事务配置可以参见下面的代码例子:
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   
   
   
       
            PROPAGATION_REQUIRED,-MyCheckedException
            PROPAGATION_REQUIRED
            PROPAGATION_REQUIRED,readOnly
       

   


在上面的代码中定义了someBusinessBean这个bean,其中target属性中定义实际的业务接口实现类。并且在transactionAttributes属性中针对method进行事务声明,最常用的声明是PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。另外可以定义只读事务readOnly,用于只读的数据库操作。同时我们还注意到事务定义中包含了异常情况的配置:如果出现MyCheckedException这个自定义异常,则数据库进行回滚。
还有一种方式是继承式事务定义,例子如下:
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
       
       
           
                PROPAGATION_REQUIRED,-MyCheckedException
                PROPAGATION_REQUIRED,-MyCheckedException
                PROPAGATION_REQUIRED,readOnly
           

       

   

   
       
           
               
           

       

   
   
  可以看出,这种方式先使用一个父类作为事务控制的统一定义,然后具体的业务bean通过继承来实现事务的配置。其实这2中配置方式并没有本质的区别,只是第二种定义起来会省事一点。
  另外在实际项目中有一个发现,在websphere6.0的容器下部署的web应用,使用websphere自带的数据库连接池,当spring事务配置为readOnly,在数据量比较大,并且有一定并发量时会导致websphere连接池抛出异常,并导致性能严重下降。去掉readOnly选项就恢复正常了,这种情况不容易在测试环境重现,因此只能去掉readOnly选项,发现去掉以后性能也没有太多的下降。
  另外如果一些特殊的场景直接在代码中进行事务提交(比如大批量插入数据),则需要用到spring的编程事务,PlatformTransactionManager这个类是spring针对编程式事务的支持类。

  4 spring与数据库连接池
    在spring中可以很方便的配置数据库连接池,一种是直接配置连接池,以proxool连接池为例,配置代码如下:
   
    mydb
        test
        test
        com.mysql.jdbc.Driver
        jdbcUrl
        10
        20
        1
        90000                       
   
   
    如上,在配置文件中定义了dataSource这个bean,映射到ProxoolDataSource这个proxool的数据库数据源的实现类,在属性里的配置就是连接池的一些基本参数
    我想更常用的还是使用jndi作为数据源,配置代码如下:
   
        jdbc/mydblink
   
   
    在上面的代码中使用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的地方,相信还有更多的没有列举出来,在以后的文章里再补充吧