blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/xzclog/category/17330.htmlzh-cntue, 09 aug 2011 21:11:52 gmttue, 09 aug 2011 21:11:52 gmt60spring事务管理与数据库连接http://www.blogjava.net/xzclog/archive/2011/08/09/356124.htmlxzcxzctue, 09 aug 2011 06:59:00 gmthttp://www.blogjava.net/xzclog/archive/2011/08/09/356124.htmlhttp://www.blogjava.net/xzclog/comments/356124.htmlhttp://www.blogjava.net/xzclog/archive/2011/08/09/356124.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/356124.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/356124.html转自:
前几天解释了spring的抽象事务机制。这次讲讲spring中的datasource 事务。
datasource事务相关的类比较多,我们一步步来拨开其中的密团。

1 如何获得连接
看datasourceutils代码
java代码  
  1. protected static connection dogetconnection(datasource datasource, boolean allowsynchronization);   
  2.             throws sqlexception {   
  3.            
  4.         connectionholder conholder = (connectionholder); transactionsynchronizationmanager.getresource(datasource);;   
  5.         if (conholder != null); {   
  6.             conholder.requested();;   
  7.             return conholder.getconnection();;   
  8.         }   
  9.   
  10.            
  11.         connection con = datasource.getconnection();;   
  12.         if (allowsynchronization && transactionsynchronizationmanager.issynchronizationactive();); {   
  13.                         conholder = new connectionholder(con);;   
  14.             transactionsynchronizationmanager.bindresource(datasource, conholder);;   
  15.             transactionsynchronizationmanager.registersynchronization(new connectionsynchronization(conholder, datasource););;   
  16.             conholder.requested();;   
  17.         }   
  18.   
  19.         return con;   
  20.     }  

原来连接是从transactionsynchronizationmanager中获取,如果transactionsynchronizationmanager中已经有了,那么拿过来然后调用conholder.requested()。否则从原始的datasource这创建一个连接,放到一个connectionholder,然后再调用transactionsynchronizationmanager.bindresource绑定。
好,我们又遇到两个新的类transactionsynchronizationmanager和connectionholder和。继续跟踪


2 transactionsynchronizationmanager
看其中的一些代码
java代码  
  1. private static threadlocal resources = new threadlocal();;   
  2. public static object getresource(object key); {   
  3.         map map = (map); resources.get();;   
  4.         if (map == null); {   
  5.             return null;   
  6.         }   
  7.         object value = map.get(key);;   
  8.                 return value;   
  9.     }   
  10. public static void bindresource(object key, object value); throws illegalstateexception {   
  11.         map map = (map); resources.get();;   
  12.                 if (map == null); {   
  13.             map = new hashmap();;   
  14.             resources.set(map);;   
  15.         }   
  16.         map.put(key, value);;   
  17.             }  
原来transactionsynchronizationmanager内部建立了一个threadlocal的resources,这个resources又是和一个map联系在一起的,这个map在某个线程第一次调用bindresource时生成。
联系前面的datasourceutils代码,我们可以总结出来。
某个线程使用datasourceutils,当第一次要求创建连接将在transactionsynchronizationmanager中创建出一个threadlocal的map。然后以datasource作为键,connectionholder为值放到map中。等这个线程下一次再请求的这个datasource的时候,就从这个map中获取对应的connectionholder。用map是为了解决同一个线程上多个datasource。
然后我们来看看connectionholder又是什么?



3 对连接进行引用计数
看connectionholder代码,这个类很简单,看不出个所以然,只好再去看父类代码resourceholdersupport,我们感兴趣的是这两个方法
java代码  
  1. public void requested(); {   
  2.         this.referencecount ;   
  3.     }   
  4.   
  5.     public void released(); {   
  6.         this.referencecount--;   
  7.     }  

看得出这是一个引用计数的技巧。原来spring中对connection是竟量使用已创建的对象,而不是每次都创建一个新对象。这就是datasourceutils中
java代码  
  1. if (conholder != null); {   
  2.             conholder.requested();;   
  3.             return conholder.getconnection();;   
  4.         }  
的原因


4 释放连接
完成事物后datasourcetransactionmanager有这样的代码
java代码  
  1. protected void docleanupaftercompletion(object transaction); {   
  2.         datasourcetransactionobject txobject = (datasourcetransactionobject); transaction;   
  3.   
  4.         // remove the connection holder from the thread.   
  5.         transactionsynchronizationmanager.unbindresource(this.datasource);;   
  6.         txobject.getconnectionholder();.clear();;   
  7.   
  8.         //...       datasourceutils.closeconnectionifnecessary(con, this.datasource);;   
  9.     }  

datasourceutils
java代码  
  1. protected static void docloseconnectionifnecessary(connection con, datasource datasource); throws sqlexception {   
  2.         if (con == null); {   
  3.             return;   
  4.         }   
  5.   
  6.         connectionholder conholder = (connectionholder); transactionsynchronizationmanager.getresource(datasource);;   
  7.         if (conholder != null && con == conholder.getconnection();); {   
  8.             // it's the transactional connection: don't close it.   
  9.             conholder.released();;   
  10.             return;   
  11.         }   
  12.            
  13.         // leave the connection open only if the datasource is our   
  14.         // special data source, and it wants the connection left open.   
  15.         if (!(datasource instanceof smartdatasource); || ((smartdatasource); datasource);.shouldclose(con);); {   
  16.             logger.debug("closing jdbc connection");;   
  17.             con.close();;   
  18.         }   
  19.     }  

恍然大悟。如果事物完成,那么就
transactionsynchronizationmanager.unbindresource(this.datasource);将当前的connectionholder
从transactionsynchronizationmanager上脱离,然后docloseconnectionifnecessary。最后会把连接关闭掉。

5 两个辅助类jdbctemplate和transactionawaredatasourceproxy
jdbctemplate中的execute方法的第一句和最后一句
java代码  
  1. public object execute(preparedstatementcreator psc, preparedstatementcallback action);   
  2.             throws dataaccessexception {   
  3.   
  4.         connection con = datasourceutils.getconnection(getdatasource(););;   
  5.         //其他代码   
  6.     datasourceutils.closeconnectionifnecessary(con, getdatasource(););;   
  7.         }   
  8.     }  

作用不言自明了吧

从transactionawaredatasourceproxy中获取的连接是这个样子的
java代码  
  1. public connection getconnection(); throws sqlexception {   
  2.         connection con = datasourceutils.dogetconnection(gettargetdatasource();, true);;   
  3.         return gettransactionawareconnectionproxy(con, gettargetdatasource(););;   
  4.     }  

万变不离其宗,不过我们还是看看gettransactionawareconnectionproxy
java代码  
  1. protected connection gettransactionawareconnectionproxy(connection target, datasource datasource); {   
  2.         return (connection); proxy.newproxyinstance(   
  3.                 connectionproxy.class.getclassloader();,   
  4.                 new class[] {connectionproxy.class},   
  5.                 new transactionawareinvocationhandler(target, datasource););;   
  6.     }  

原来返回的是jdk的动态代理。继续看transactionawareinvocationhandler
java代码  
  1. public object invoke(object proxy, method method, object[] args); throws throwable {   
  2.         //...           if (method.getname();.equals(connection_close_method_name);); {   
  3.                 if (this.datasource != null); {   
  4.                     datasourceutils.docloseconnectionifnecessary(this.target, this.datasource);;   
  5.                 }   
  6.                 return null;   
  7.             }   
  8.   
  9.                     }  

transactionawaredatasourceproxy会先从datasourceutils获取连接。然后将这个连接用jdk的动态代理包一下返回。外部代码如果调用的这个冒牌的connection,就会先调用transactionawareinvocationhandler的invoke,在这个invoke 中,完成原来调用datasourceutils的功能。

总结上面的流程
spring 对datasource进行事务管理的关键在于connectionholder和transactionsynchronizationmanager。
  0.先从transactionsynchronizationmanager中尝试获取连接
  1.如果前一步失败则在每个线程上,对每个datasouce只创建一个connection
   2.这个connection用connectionholder包装起来,由transactionsynchronizationmanager管理
  3.再次请求同一个连接的时候,从transactionsynchronizationmanager返回已经创建的connectionholder,然后调用connectionholder的request将引用计数 1
  4.释放连接时要调用connectionholder的released,将引用计数-1
  5.当事物完成后,将connectionholder从transactionsynchronizationmanager中解除。当谁都不用,这个连接被close

以上所有都是可以调用datasourceutils化简代码,而jdbctemplate又是调用datasourceutils的。所以在spring文档中要求尽量首先使用jdbctemplate,其次是用datasourceutils来获取和释放连接。至于transactionawaredatasourceproxy,那是下策的下策。不过可以将spring事务管理和遗留代码无缝集成。

所以如某位朋友说要使用spring的事务管理,但是又不想用jdbctemplate,那么可以考虑transactionawaredatasourceproxy。这个类是原来datasource的代理。
其次,想使用spring事物,又不想对spring进行依赖是不可能的。与其试图自己模拟datasourceutils,不如直接使用现成的。


xzc 2011-08-09 14:59
]]>
j2ee异常处理机制http://www.blogjava.net/xzclog/archive/2010/03/13/315329.htmlxzcxzcsat, 13 mar 2010 03:59:00 gmthttp://www.blogjava.net/xzclog/archive/2010/03/13/315329.htmlhttp://www.blogjava.net/xzclog/comments/315329.htmlhttp://www.blogjava.net/xzclog/archive/2010/03/13/315329.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/315329.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/315329.htmlhttp://mofeichen.javaeye.com/blog/557426

异常的处理是每个java程序员时常面对的问题,但是很多人没有原则,遇到异常也不知道如何去处理,于是遇到检查异常就胡乱try...catch...一把,然后e.printstacktrace()一下了事,这种做法通常除了调试排错有点作用外,没任何价值。对于运行时异常,则干脆置之不理。

  原因是很多开发者缺乏对异常的认识和分析,首先应该明白java异常体系结构,一种分层继承的关系,你必须对层次结构熟烂于心:

  throwable(必须检查)

  error(非必须检查)

  exception(必须检查)

  runtimeexception(非必须检查)

  一般把exception异常及其直接子类(除了runtimeexception之外)的异常称之为检查异常。把runtimeexception以及其子类的异常称之为非检查异常,也叫运行时异常。

  对于throwable和error,则用的很少,一般会用在一些基础框架中,这里不做讨论。

  下面针对j2ee的分层架构:dao层、业务层、控制层、展示层的异常处理做个分析,并给出一般处理准则。

  一、dao层异常处理

  如果你用了spring的dao模板来实现,则dao层没有检查异常抛出,代码非常的优雅。但是,如果你的dao采用了原始的jdbc来写,这时候,你不能不对异常做处理了,因为难以避免的sqlexception会如影随形的跟着你。对已这种dao级别的异常,异常了你又能如何呢?与其这样胡乱try...catch...,囫囵吞枣消灭了异常不如让异常以另外一种非检查的方式向外传递。这样做好处有二:

  1)、dao的接口不被异常所污染,假设你抛出了sqlexception,以后要是换了spring dao模板,那dao接口就不再抛出了sqlexception,这样,你的接口抛出异常就是对接口的污染。

  2)、dao异常向外传播给更高层处理,以便异常的错误原因不丢失,便于排查错误或进行捕获处理。

  这里还有一个设计上常常令人困扰的问题:很多人会问,那定义一个什么样的异常抛出呢,或者是直接抛出一个throw runtimeexception(e)? 对于这个问题,需要分场合,如果系统小,你可以直接抛出一个throw runtimeexception(e),但对于一个庞大的多模块系统来说,不要抛这种原生的非检查异常,而要抛出自定义的非检查异常,这样不但利于排错,而且有利于系统异常的处理,通常针对每一个模块,粗粒度的定义一个运行时dao异常。比如:throw new modelxxxdaoruntimeexception(".....",e),对于msg信息,你可写也可不写,根据需要灵活抛出。

  这里常见一个很愚昧的处理方式,为每个dao定义一个异常,呵呵,这样累不累啊,有多大意义,在service层中调用时候,如果要捕获,还要捕获出一堆异常。这样致命的问题是代码混乱,维护困难,阅读也困难,dao的异常应该是粗粒度的。

  二、业务层异常处理

  习惯上把业务层称之为service层或者服务层,service层的代表的是业务逻辑,不要迷信分太多太多层有多大好处,除非需要,否则别盲目划分不必要的层,层越多,效率越差,根据需要够用就行了。

  service接口中的每个方法代表一个特定的业务,而这个业务一定是一个完整的业务,通常会看到一些傻x的做法,数据库事务配置在service层,而service的实现就是dao的直接调用,然后在控制层(action)中,调用了好多service去完成一个业务,你气得已经无语了,低头找砖头去!!!

  搞明白以上两个问题后再回过头看异常怎么处理,service层通常依赖dao,而service层的通常也会因为调用别的非检查异常方法而必须面对异常处理的问题,这里和dao层又有所不同,彼一时,此一时嘛!

  一般来说一个小模块对应一个service,当然也许有两个或多个,针对这个模块的service定义一个非检查异常,以应付那些不可避免的异常检查,这个自定义异常可以简单的命名为xxxserviceruntimeexception,将捕获到的异常顺势转译为非检查异常后抛出。我喜欢这么做,因为前台是j2ee应用,前台是web页面,它们的struts2等框架会自动捕获所有service层的异常,并把异常交给开发者去自由处理。

  但是还有一种情况,由于一些特殊的限制,如果某个异常一旦发生,必须做什么什么处理,而这种处理时硬性要求,或者调用某个service方法,必须检查处理什么异常,也可以抛出非检查的自定义异常,往往出现这种情况的是政治原因。不推崇这种做法,但也不排斥。

  总之,对于接口,尽可能不去用异常污染她!

  三、控制层异常

  控制层说的简单些就是常见的action层,主要是控制页面请求的处理。控制层通常都依赖于service层,现在比较流行的框架对控制层做得都相当的到位,比如struts2、springmvc等等,他们的控制层框架会捕获业务层的所有异常,并在控制层中声明可能抛出exception,因此控制层一般不处理什么异常。

  如果是控制层中因为调用了一些非检查异常的方法,比如io操作等,可以简单处理下异常,保证流的安全,这才是目的。

  四、显示层异常处理

  对于页面异常,处理的方式多种多样,一是不处理异常,一旦异常了,页面就报错。二是定义出错页面,根据异常的类型以及所在的模块,导航到出错页面。

  一般来说,出错页面是更友好的做法。

  另外还有特殊的处理方式,展示页面的模板可以捕获异常,并根据情况将异常信息铺到相应的位置,这样就更友好了,不过复杂度较高。

  怎么处理,就看需要了。

  五、总结

  1)、对于异常处理,应该从设计、需要、维护等多个角度综合考虑,有一个通用准则:千万别捕获了异常什么事情都不干,这样一旦出现异常了,你没法依据异常信息来排错。

  2)、对于j2ee多层架构系统来说,尽可能避免(因抛出异常带来的)接口污染。



xzc 2010-03-13 11:59
]]>
proxool连接池配置详细说明http://www.blogjava.net/xzclog/archive/2010/01/30/311320.htmlxzcxzcsat, 30 jan 2010 04:02:00 gmthttp://www.blogjava.net/xzclog/archive/2010/01/30/311320.htmlhttp://www.blogjava.net/xzclog/comments/311320.htmlhttp://www.blogjava.net/xzclog/archive/2010/01/30/311320.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/311320.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/311320.htmlc3p0>dbcp,proxool还提供了可视化的连接池实时监控工具,所以既稳定又方便,配置也是非常容易的事情。下面我来讲讲我如何配置proxool连接池的。       1、下载相关资源。       从http://pr...  

xzc 2010-01-30 12:02
]]>
hibernate的三种连接池设置c3p0、proxool和dbcp http://www.blogjava.net/xzclog/archive/2010/01/30/311319.htmlxzcxzcsat, 30 jan 2010 04:00:00 gmthttp://www.blogjava.net/xzclog/archive/2010/01/30/311319.htmlhttp://www.blogjava.net/xzclog/comments/311319.htmlhttp://www.blogjava.net/xzclog/archive/2010/01/30/311319.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/311319.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/311319.html
xml代码
  1.   
  2. <property name="connection.driver_class">com.mysql.jdbc.driverproperty> <property name="connection.url">jdbc:mysql://localhost:3306/struts?useunicode=true&characterencoding=gbkproperty>   
  3. <property name="connection.username">rootproperty>   
  4. <property name="connection.password">8888property>   


上面的一段配置,在c3p0dbcp中,都是必需的,因为hibernate会根据上述的配置来生成connections,再交给c3p0dbcp管理.

1 c3p0

只需在hibernate.cfg.xml中加入
xml代码
  1. <property name="c3p0.min_size">5property>  
  2. <property name="c3p0.max_size">30property>  
  3. <property name="c3p0.time_out">1800property>  
  4. <property name="c3p0.max_statement">50property>   


还有在classespath中加入c3p0-0.8.4.5.jar


2 dbcp

在hibernate.cfg.xml中加入

xml代码
  1. <property name="dbcp.maxactive">100property>  
  2. <property name="dbcp.whenexhaustedaction">1property>  
  3. <property name="dbcp.maxwait">60000property>  
  4. <property name="dbcp.maxidle">10property>  
  5.   
  6. <property name="dbcp.ps.maxactive">100property>  
  7. <property name="dbcp.ps.whenexhaustedaction">1property>  
  8. <property name="dbcp.ps.maxwait">60000property>  
  9. <property name="dbcp.ps.maxidle">10property>  

还有在classespath中加入commons-pool-1.2.jar 和commons-dbcp-1.2.1.jar.


3 proxool

由于数据库connection在较长时间没有访问下会自动断开连接,导致浏览出错,增加proxool作为数据库pool。它有自动连接功能。
1)、从
下载proxool,释放proxool.jar到web-inf/lib

2)、在hibernate.cfg.xml中增加:
xml代码
  1. <property name="hibernate.proxool.pool_alias">dbpoolproperty>  
  2. <property name="hibernate.proxool.xml">proxool.xmlproperty>  
  3. <property name="connection.provider_class">org.hibernate.connection.proxoolconnectionproviderproperty>  


3)、在与hibernate.cfg.xml同级目录(src根目录下)增加proxool.xml文件:
xml代码
  1. xml version="1.0" encoding="utf-8"?>  
  2. public class appcontext {

      
    private static appcontext instance;

      
    private abstractapplicationcontext appcontext;

      
    public synchronized static appcontext getinstance() {
        
    if (instance == null) {
          instance 
    = new appcontext();
        }
        
    return instance;
      }

      
    private appcontext() {
        
    this.appcontext = new classpathxmlapplicationcontext(
            
    "/applicationcontext.xml");
      }

      
    public abstractapplicationcontext getappcontext() {
        
    return appcontext;
      }
    }

不过这样,还是加载了2次applicationcontext,servlet一次,路径加载一次;觉得不如直接用路径加载,舍掉servlet加载
在网上也找了些其他说法:实现applicationcontextaware,,, 接口,或者servletcontextaware接口,还要写配置文件。有的竟然要把配置文件里的listener,换成自己的类,这样纯粹多此一举。不过有的应用不是替换,是在补一个listener,
我在一版的jpetstore(具体那一版不知道)里发现了这个:
[web.xml]里
     
    <listener>
        
<listener-class>org.springframework.web.context.contextloaderlistenerlistener-class>
    
listener>
    
    
<listener>
        
<listener-class>com.ibatis.jpetstore.util.springinitlistener-class>
    
listener>
其中springinit实现接口servletcontextlistener

package com.ibatis.jpetstore.util;

import javax.servlet.servletcontextevent;
import javax.servlet.servletcontextlistener;
import org.springframework.context.applicationcontext;
import org.springframework.web.context.webapplicationcontext;
import org.springframework.web.context.support.webapplicationcontextutils;


public class springinit implements servletcontextlistener {
    

    
private static webapplicationcontext springcontext;
    
    
public springinit() {
        
super();
    }
    
    
public void contextinitialized(servletcontextevent event) {
        springcontext 
= webapplicationcontextutils.getwebapplicationcontext(event.getservletcontext());
    }
    

    
public void contextdestroyed(servletcontextevent event) {
    }
    
    
public static applicationcontext getapplicationcontext() {
        
return springcontext;
    }

    
}

在其中的一个bean的构造里springinit获取applicationcontext,代码:
  public orderbean() {
    
this(
            (accountservice) springinit.getapplicationcontext().getbean(
"accountservice"),
            (orderservice) springinit.getapplicationcontext().getbean(
"orderservice") );
  }

恩,这种在action,servlet之外的bean里获取applicationcontext的方法值得参考,应该有用


xzc 2009-10-22 18:02
]]>
spring 2.5 标注开发的简单例子http://www.blogjava.net/xzclog/archive/2009/06/25/284109.htmlxzcxzcthu, 25 jun 2009 07:06:00 gmthttp://www.blogjava.net/xzclog/archive/2009/06/25/284109.htmlhttp://www.blogjava.net/xzclog/comments/284109.htmlhttp://www.blogjava.net/xzclog/archive/2009/06/25/284109.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/284109.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/284109.html研究了很久新出的 spring 2.5, 总算大致明白了如何用标注定义 bean, 但是如何定义和注入类型为 java.lang.string 的 bean 仍然未解决, 希望得到高人帮助.

总的来看 java ee 5 的标注开发方式开来是得到了大家的认可了.

@service 相当于定义 bean, 自动根据 bean 的类名生成一个首字母小写的 bean

@autowired 则是自动注入依赖的类, 它会在类路径中找成员对应的类/接口的实现类, 如果找到多个, 需要用 @qualifier("chineseman") 来指定对应的 bean 的 id.

一定程度上大大简化了代码的编写, 例如一对一的 bean 映射现在完全不需要写任何额外的 bean 定义了.

下面是代码的运行结果:

man.sayhello()=抽你丫的
simpleman said: hi
org.example.englishman@12bcd4b said: fuck you!

 

代码:

beans.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:context="http://www.springframework.org/schema/context"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.example"/>
beans>

测试类:

import org.example.iman;
import org.example.simpleman;
import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;

public class springtest {
    public static void main(string[] args) {
        applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml");
        simpleman dao = (simpleman) ctx.getbean("simpleman");
        system.out.println(dao.hello());
        iman man = (iman) ctx.getbean("usman");
        system.out.println(man.sayhello());
    }
}

自动探测和注入bean的类:

package org.example;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.stereotype.service;

@service
public class simpleman {
    // 自动注入名称为 man 的 bean
    @autowired(required = false)
    @qualifier("chineseman")
    //@qualifier("usman")
    private iman man;   

    /**
     * @return the man
     */
    public iman getman() {
        return man;
    }

    /**
     * @param man the man to set
     */
    public void setman(iman man) {
        this.man = man;
    }

    public string hello() {
        system.out.println("man.sayhello()=" man.sayhello());
        return "simpleman said: hi";
    }
}

 

一个接口和两个实现类:

package org.example;

/**
* 抽象的人接口.
* @author beansoft
* @version 1.0
*/
public interface iman {
    /**
     * 打招呼的抽象定义.
     * @return 招呼的内容字符串
     */
    public string sayhello();
}

 

package org.example;

import org.springframework.stereotype.service;

/**
* 中国人的实现.
* @author beansoft
*/
@service
public class chineseman implements iman {

    public string sayhello() {
        return "抽你丫的";
    }

}

 

package org.example;

import org.springframework.stereotype.service;

/**
* @author beansoft
* 美国大兵
*/
@service("usman")
// 这里定义了一个 id 为 usman 的 bean, 标注里面的属性是 bean 的 id
public class englishman implements iman {

    public string sayhello() {
        return this " said: fuck you!";
    }

}



xzc 2009-06-25 15:06
]]>
spring中autowire属性http://www.blogjava.net/xzclog/archive/2009/06/25/284065.htmlxzcxzcthu, 25 jun 2009 01:44:00 gmthttp://www.blogjava.net/xzclog/archive/2009/06/25/284065.htmlhttp://www.blogjava.net/xzclog/comments/284065.htmlhttp://www.blogjava.net/xzclog/archive/2009/06/25/284065.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/284065.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/284065.html spring中autowire属性
default-autowire="x"
x有4个选择:byname,bytype,constructor和autodetect

我感觉byname和bytype用的多点

1. byname:

service.java

public class service
{
    source source;

    public void setsource(source source)
    {
        this.source = source;
    }
}


applicationcontext.xml

<beans

   ...

   default-autowire="byname">
   
    <bean id="source" class="cn.hh.spring.dbcpsource" scope="prototype"/>
    <bean id="service" class="cn.hh.spring.service" scope="prototype">
    </bean>
</beans>


cn.hh.spring.dbcpsource实现了source接口
xml中并没有给 bean service配source属性,但在beans中设置了autowire="byname",这样配置文件会自动根据 cn.hh.spring.service 中的setsource找bean id="source"的bean ,然后自动配上去,如果没找到就不装配。
注意:byname的name是java中setxxxx 的xxxx, 和上面设置的source source中source拼写毫无关系,完全可以是

public class service
{
    source source1;

    public void setsource(source source1)
    {
        this.source1 = source1;
    }

}


结果相同。

2. bytype:

service.java同上

applicationcontext.xml

<beans
   ...
   default-autowire="bytype">
   
    <bean id="dbcpsource" class="cn.hh.spring.dbcpsource" scope="prototype"/>
    <bean id="service" class="cn.hh.spring.service" scope="prototype">
    </bean>
</beans>


同样没有配置setsource,autowire改成 "bytype",配置文件会找实现了source接口的bean,这里 cn.hh.spring.dbcpsource 实现了source接口,所以自动装配,如果没找到则不装配。
如果同个配制文件中两个bean实现了source接口,则报错。
这里的 type是指setsource(source source)中参数的类型。

3. constructor:

试图在容器中寻找与需要自动装配的bean的构造函数参数一致的一个或多个bean,如果没找到则抛出异常。


4. autodetect:

首先尝试使用constructor来自动装配,然后再使用bytype方式。


xzc 2009-06-25 09:44
]]>
spring的applicationcontext.xml文件http://www.blogjava.net/xzclog/archive/2008/06/07/206514.htmlxzcxzcsat, 07 jun 2008 05:48:00 gmthttp://www.blogjava.net/xzclog/archive/2008/06/07/206514.htmlhttp://www.blogjava.net/xzclog/comments/206514.htmlhttp://www.blogjava.net/xzclog/archive/2008/06/07/206514.html#feedback1http://www.blogjava.net/xzclog/comments/commentrss/206514.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/206514.htmlspring的程序员们都有这样的感觉,spring把逻辑层封装的太完美了(个人感觉view层封装的不是很好)。以至于有的初学者都不知道spring配置文件的意思,就拿来用了。所以今天我给大家详细解释一下spring的applicationcontext.xml。ok,我还是通过代码加注释的方式为大家演示:
以下是详解spring的applicationcontext.xml文件代码:




 
 
  
  
   com.mysql.jdbc.driver
  

  
  
   
       jdbc:mysql://localhost:3306/tie?useunicode=true&characterencoding=utf-8
  

  

  
  
   root
  

  
  
   123
  

 

 
    class="org.springframework.orm.hibernate3.localsessionfactorybean">
  
   
  

  
  
   
    com/alonely/vo/user.hbm.xml
   

  

 

 
 

    class="org.springframework.orm.hibernate3.hibernatetemplate">
  
   
  

 

 
 
  
   
  

 

 
 
  
   
  

 

 
 
  
   
  

 

以上spring的applicationcontext.xml文件我是用的ssh架构,如果您用spring的架构,其原理也是一样的。

xzc 2008-06-07 13:48
]]>
jdbctemplate学习笔记http://www.blogjava.net/xzclog/archive/2008/06/07/206512.htmlxzcxzcsat, 07 jun 2008 05:37:00 gmthttp://www.blogjava.net/xzclog/archive/2008/06/07/206512.htmlhttp://www.blogjava.net/xzclog/comments/206512.htmlhttp://www.blogjava.net/xzclog/archive/2008/06/07/206512.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/206512.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/206512.html
java代码
  1. jdbctemplate.execute("create table user (user_id integer, name varchar(100))");  

2、如果是update或insert,可以用update()方法。
java代码
  1. jdbctemplate.update("insert into user values('"  
  2.              user.getid()   "', '"  
  3.              user.getname()   "', '"  
  4.              user.getsex()   "', '"  
  5.              user.getage()   "')");  

3、带参数的更新
java代码
  1. jdbctemplate.update("update user set name = ? where user_id = ?"new object[] {name, id});  

java代码
  1. jdbctemplate.update("insert into user values(?, ?, ?, ?)"new object[] {user.getid(), user.getname(), user.getsex(), user.getage()});  

4、使用jdbctemplate进行查询时,使用queryforxxx()等方法
java代码
  1. int count = jdbctemplate.queryforint("select count(*) from user");  


java代码
  1. string name = (string) jdbctemplate.queryforobject("select name from user where user_id = ?"new object[] {id}, java.lang.string.class);  


java代码
  1. list rows = jdbctemplate.queryforlist("select * from user");  


java代码
  1. list rows = jdbctemplate.queryforlist("select * from user");   
  2. iterator it = rows.iterator();   
  3. while(it.hasnext()) {   
  4.     map usermap = (map) it.next();   
  5.     system.out.print(usermap.get("user_id")   "\t");   
  6.     system.out.print(usermap.get("name")   "\t");   
  7.     system.out.print(usermap.get("sex")   "\t");   
  8.     system.out.println(usermap.get("age")   "\t");   
  9. }  


jdbctemplate将我们使用的jdbc的流程封装起来,包括了异常的捕捉、sql的执行、查询结果的转换等等。spring大量使用template method模式来封装固定流程的动作,xxxtemplate等类别都是基于这种方式的实现。
除了大量使用template method来封装一些底层的操作细节,spring也大量使用callback方式类回调相关类别的方法以提供jdbc相关类别的功能,使传统的jdbc的使用者也能清楚了解spring所提供的相关封装类别方法的使用。

jdbc的preparedstatement
java代码
  1. final string id = user.getid();   
  2. final string name = user.getname();   
  3. final string sex = user.getsex()   "";   
  4. final int age = user.getage();   
  5.   
  6. jdbctemplate.update("insert into user values(?, ?, ?, ?)",   
  7.                      new preparedstatementsetter() {   
  8.                          public void setvalues(preparedstatement ps) throws sqlexception {   
  9.                              ps.setstring(1, id);   
  10.                              ps.setstring(2, name);             
  11.                              ps.setstring(3, sex);   
  12.                              ps.setint(4, age);   
  13.                          }   
  14.                      });  


java代码
  1. final user user = new user();   
  2. jdbctemplate.query("select * from user where user_id = ?",   
  3.                     new object[] {id},   
  4.                     new rowcallbackhandler() {   
  5.                         public void processrow(resultset rs) throws sqlexception {   
  6.                             user.setid(rs.getstring("user_id"));   
  7.                             user.setname(rs.getstring("name"));   
  8.                             user.setsex(rs.getstring("sex").charat(0));   
  9.                             user.setage(rs.getint("age"));   
  10.                         }   
  11.                     });  




java代码
  1. class userrowmapper implements rowmapper {   
  2.     public object maprow(resultset rs, int index) throws sqlexception {   
  3.         user user = new user();   
  4.   
  5.         user.setid(rs.getstring("user_id"));   
  6.         user.setname(rs.getstring("name"));   
  7.         user.setsex(rs.getstring("sex").charat(0));   
  8.         user.setage(rs.getint("age"));   
  9.   
  10.         return user;   
  11.     }   
  12. }   
  13.   
  14. public list findallbyrowmapperresultreader() {   
  15.     string sql = "select * from user";   
  16.     return jdbctemplate.query(sql, new rowmapperresultreader(new userrowmapper()));   
  17. }  


在getuser(id)里面使用userrowmapper
java代码
  1. public user getuser(final string id) throws dataaccessexception {   
  2.     string sql = "select * from user where user_id=?";   
  3.     final object[] params = new object[] { id };   
  4.     list list = jdbctemplate.query(sql, params, new rowmapperresultreader(new userrowmapper()));   
  5.   
  6.     return (user) list.get(0);   
  7. }  


网上收集
org.springframework.jdbc.core.preparedstatementcreator 返回预编译sql 不能于object[]一起用
java代码
  1. public preparedstatement createpreparedstatement(connection con) throws sqlexception {   
  2.  return con.preparestatement(sql);   
  3. }  

1.增删改
org.springframework.jdbc.core.jdbctemplate 类(必须指定数据源datasource)
java代码
  1. template.update("insert into web_person values(?,?,?)",object[]);  


java代码
  1. template.update("insert into web_person values(?,?,?)",new preparedstatementsetter(){ 匿名内部类 只能访问外部最终局部变量   
  2.   
  3.  public void setvalues(preparedstatement ps) throws sqlexception {   
  4.   ps.setint(index ,3);   
  5. });  

org.springframework.jdbc.core.preparedstatementsetter 接口 处理预编译sql
java代码
  1. public void setvalues(preparedstatement ps) throws sqlexception {   
  2.  ps.setint(index ,3);   
  3. }  

2.查询jdbctemplate.query(string,[object[]/preparedstatementsetter],rowmapper/rowcallbackhandler)
org.springframework.jdbc.core.rowmapper 记录映射接口 处理结果集
java代码
  1. public object maprow(resultset rs, int arg1) throws sqlexception {   int表当前行数   
  2.   person.setid(rs.getint("id"));   
  3. }   
  4. list template.query("select * from web_person where id=?",object[],rowmapper);  

org.springframework.jdbc.core.rowcallbackhandler 记录回调管理器接口 处理结果集
java代码
  1. template.query("select * from web_person where id=?",object[],new rowcallbackhandler(){   
  2.  public void processrow(resultset rs) throws sqlexception {   
  3.   person.setid(rs.getint("id"));   
  4. });  


xzc 2008-06-07 13:37
]]>
java读取配置文件的几种方法http://www.blogjava.net/xzclog/archive/2008/06/06/206354.htmlxzcxzcfri, 06 jun 2008 07:56:00 gmthttp://www.blogjava.net/xzclog/archive/2008/06/06/206354.htmlhttp://www.blogjava.net/xzclog/comments/206354.htmlhttp://www.blogjava.net/xzclog/archive/2008/06/06/206354.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/206354.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/206354.html一.读取xml配置文件
(一)新建一个java bean(hellobean.java)
java 代码
  1. package chb.demo.vo;   
  2.   
  3. public class hellobean {   
  4.  private string helloworld;   
  5.   
  6.  public string gethelloworld() {   
  7.   return helloworld;   
  8.  }   
  9.   
  10.  public void sethelloworld(string helloworld) {   
  11.   this.helloworld = helloworld;   
  12.  }   
  13. }   
  14.   

(二)构造一个配置文件(beanconfig.xml)

xml 代码
  1. xml version="1.0" encoding="utf-8"?>  
  2. >  
  3. <beans>  
  4.  <bean id="hellobean" class="chb.demo.vo.hellobean">  
  5.   <property name="helloworld">  
  6.    <value>hello!chb!value>  
  7.   property>  
  8.  bean>  
  9. beans>  

(三)读取xml文件

1.利用classpathxmlapplicationcontext
java 代码
  1. applicationcontext context = new classpathxmlapplicationcontext("beanconfig.xml");   
  2. hellobean hellobean = (hellobean)context.getbean("hellobean");   
  3. system.out.println(hellobean.gethelloworld());  
2.利用filesystemresource读取
java 代码
  1. resource rs = new filesystemresource("d:/software/tomcat/webapps/springwebdemo/web-inf/classes/beanconfig.xml");   
  2.   beanfactory factory = new xmlbeanfactory(rs);   
  3.   hellobean hellobean = (hellobean)factory.getbean("hellobean");\   
  4.   system.out.println(hellobean.gethelloworld());   
 值得注意的是:利用filesystemresource,则配置文件必须放在project直接目录下,或者写明绝对路径,否则就会抛出找不到文件的异常
二.读取properties配置文件
这里介绍两种技术:利用spring读取properties 文件和利用java.util.properties读取
(一)利用spring读取properties 文件
我们还利用上面的hellobean.java文件,构造如下beanconfig.properties文件:
properties 代码
  1. hellobean.class=chb.demo.vo.hellobean   
  2. hellobean.helloworld=hello!chb!  
属性文件中的"hellobean"名称即是bean的别名设定,.class用于指定类来源。
然后利用org.springframework.beans.factory.support.propertiesbeandefinitionreader来读取属性文件
java 代码
  1. beandefinitionregistry reg = new defaultlistablebeanfactory();   
  2.  propertiesbeandefinitionreader reader = new propertiesbeandefinitionreader(reg);   
  3.  reader.loadbeandefinitions(new classpathresource("beanconfig.properties"));   
  4.  beanfactory factory = (beanfactory)reg;   
  5.  hellobean hellobean = (hellobean)factory.getbean("hellobean");   
  6.  system.out.println(hellobean.gethelloworld());   
 
(二)利用java.util.properties读取属性文件
比如,我们构造一个ipconfig.properties来保存服务器ip地址和端口,如:
properties 代码
  1. ip=192.168.0.1   
  2. port=8080  
则,我们可以用如下程序来获得服务器配置信息:
java 代码
  1. inputstream inputstream = this.getclass().getclassloader().getresourceasstream("ipconfig.properties");   
  2.   properties p = new properties();   
  3.   try {   
  4.    p.load(inputstream);   
  5.   } catch (ioexception e1) {   
  6.    e1.printstacktrace();   
  7.   }   
  8. system.out.println("ip:" p.getproperty("ip") ",port:" p.getproperty("port"));  
本文只介绍了一些简单操作,不当之处希望大家多多指教


xzc 2008-06-06 15:56
]]>
spring 生成excel和pdf文件 http://www.blogjava.net/xzclog/archive/2006/10/06/73538.htmlxzcxzcfri, 06 oct 2006 07:07:00 gmthttp://www.blogjava.net/xzclog/archive/2006/10/06/73538.htmlhttp://www.blogjava.net/xzclog/comments/73538.htmlhttp://www.blogjava.net/xzclog/archive/2006/10/06/73538.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/73538.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/73538.htmlhtml页面并不总是向用户显示数据输出的最好方式,有时候需要生成不可改变的文件打印,pdf可能是种不错的选择。

spring支持从数据动态生成pdf或excel文件

下面这个简单实现的例子实现了spring输出pdf和excel文件,为了使用excel电子表格,你需要在你的classpath中加入poi-2.5.1.jar库文件,而对pdf文件,则需要itext.jar文件。它们都包含在spring的主发布包中。

下面是测试项目代码:


1、控制器配置代码
xml version="1.0" encoding="utf-8"?>
doctype beans public "-//spring//dtd bean//en" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    
<bean id="beannameviewresolver"
        class
="org.springframework.web.servlet.view.beannameviewresolver" />

    
<bean id="viewcontroller" class="com.zhupan.spring.viewcontroller" />
    
<bean id="urlmapping"
        class
="org.springframework.web.servlet.handler.simpleurlhandlermapping">
        
<property name="mappings">
            
<props>
                
<prop key="/view*.shtml">viewcontrollerprop>
            
props>
        
property>
    
bean>
beans>

 3、用于excel视图的视图子类化
为了在生成输出文档的过程中实现定制的行为,我们将继承合适的抽象类。对于excel,这包括提供一个 org.springframework.web.servlet.view.document.abstractexcelview的子类,并实现 buildexceldocument方法。
package com.zhupan.view;

import java.util.date;
import java.util.map;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;

import org.apache.poi.hssf.usermodel.hssfcell;
import org.apache.poi.hssf.usermodel.hssfcellstyle;
import org.apache.poi.hssf.usermodel.hssfdataformat;
import org.apache.poi.hssf.usermodel.hssfrow;
import org.apache.poi.hssf.usermodel.hssfsheet;
import org.apache.poi.hssf.usermodel.hssfworkbook;
import org.springframework.web.servlet.view.document.abstractexcelview;


public class viewexcel extends abstractexcelview {

  
public void buildexceldocument(
             map model, hssfworkbook workbook,
             httpservletrequest request, httpservletresponse response)
    
throws exception {
  
       hssfsheet sheet 
= workbook.createsheet("list");
       sheet.setdefaultcolumnwidth((
short12);
       
       
       hssfcell cell 
= getcell(sheet, 00);
       settext(cell, 
"spring excel test");
  
       hssfcellstyle datestyle 
= workbook.createcellstyle();
       datestyle.setdataformat(hssfdataformat.getbuiltinformat(
"m/d/yy"));
       cell 
= getcell(sheet, 10);
       cell.setcellvalue(
new date());
       cell.setcellstyle(datestyle);
       getcell(sheet, 
20).setcellvalue(458);
  
       hssfrow sheetrow 
= sheet.createrow(3);
       
for (short i = 0; i < 10; i{
             sheetrow.createcell(i).setcellvalue(i 
* 10);
       }


  }

  
}


4、用于pdf视图的视图子类化
需要象下面一样继承org.springframework.web.servlet.view.document.abstractpdfview,并实现buildpdfdocument()方法。
package com.zhupan.view;

import java.util.list;
import java.util.map;

import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;

import org.springframework.web.servlet.view.document.abstractpdfview;

import com.lowagie.text.document;
import com.lowagie.text.paragraph;
import com.lowagie.text.pdf.pdfwriter;

public class viewpdf extends abstractpdfview {
    
public void buildpdfdocument(map model, document document,
            pdfwriter writer, httpservletrequest request,
            httpservletresponse response) 
throws exception {

        list list 
= (list) model.get("list");

        
for (int i = 0; i < list.size(); i)
            document.add(
new paragraph((string) list.get(i)));
    }


}

5、其他文件
1)控制器viewcontroller
package com.zhupan.spring;

import java.util.arraylist;
import java.util.hashmap;
import java.util.list;
import java.util.map;

import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;

import org.springframework.web.servlet.modelandview;
import org.springframework.web.servlet.mvc.multiaction.multiactioncontroller;

import com.zhupan.view.viewexcel;
import com.zhupan.view.viewpdf;


public class viewcontroller extends multiactioncontroller{
     
     
public modelandview viewpdf(httpservletrequest request, httpservletresponse response) throws exception {
       list list 
= new arraylist();
       map model
=new hashmap();
       list.add(
"test1");
       list.add(
"test2");
       model.put(
"list",list);
       viewpdf viewpdf
=new viewpdf();
       
return new modelandview(viewpdf,model);
  }

     
      
public modelandview viewexcel(httpservletrequest request, httpservletresponse response) throws exception {
            list list 
= new arraylist();
        map model
=new hashmap();
        list.add(
"test1");
        list.add(
"test2");
        model.put(
"list",list);
        viewexcel viewexcel
=new viewexcel();
        
return new modelandview(viewexcel,model);
      }

}
2)web.xml
xml version="1.0" encoding="utf-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi
="http://www.w3.org/2001/xmlschema-instance"
    xsi:schemalocation
="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>

    
<display-name>springpdftestdisplay-name>
    
<servlet>
        
<servlet-name>springpdftestservlet-name>
        
<servlet-class>
            org.springframework.web.servlet.dispatcherservlet
        
servlet-class>
        
<load-on-startup>1load-on-startup>
    
servlet>

    
<servlet-mapping>
        
<servlet-name>springpdftestservlet-name>
        
<url-pattern>*.shtmlurl-pattern>
    
servlet-mapping>

    
<welcome-file-list>
        
<welcome-file>index.jspwelcome-file>
    
welcome-file-list>

web-app>

3)index.jsp
<%@ page contenttype="text/html; charset=gb2312"%>

<href="viewpdf.shtml">pdf视图打开 a>
<br>
<href="viewexcel.shtml">excel视图打开a>


xzc 2006-10-06 15:07
]]>
spring aop review http://www.blogjava.net/xzclog/archive/2006/08/19/64494.htmlxzcxzcsat, 19 aug 2006 02:23:00 gmthttp://www.blogjava.net/xzclog/archive/2006/08/19/64494.htmlhttp://www.blogjava.net/xzclog/comments/64494.htmlhttp://www.blogjava.net/xzclog/archive/2006/08/19/64494.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/64494.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/64494.html阅读全文

xzc 2006-08-19 10:23
]]>
网站地图