Spring之经验教训(一)

GD Star Rating
loading...

在现在的项目中我们使用了spring + hibernate + struts的架构,在享受aop, orm, ioc, di带来的种种便利的同时,我们亦遇到了很多莫名其妙或者说刻骨铭心的教训,今天先整理两点,日后继续补充

经验一:时刻牢记,spring、hibernate对对象 进行了动态代理,尽量不要试图在动态代理后的对象上进行反射,尤其是field!

不管是hibernate的orm还是spring的声明式事务管理,都对原来的pojo、dao进行了动态代理。虽然s、h“号称”动态代理做得天衣无缝且无色无味,但是,那只是在“绝大多数情况下”,如果想对动态代理后的对象进行反射,麻烦便来了,代码片段:

  1. public static void setCreditInfoStatus(CreditInfo info, CreditType type, CreditValidateStatus status) {
  2.     ...
  3.  
  4.     Field[] fields = CreditInfo.class.getDeclaredFields();
  5.  
  6.     for (Field f : fields) {
  7.         if (f.isAnnotationPresent(Credit.class) && f.getAnnotation(Credit.class).value() == type) {
  8.             PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(CreditInfo.class, f.getName());
  9.             if (pd != null)  {
  10.                 ...
  11.             }
  12.             break;
  13.         }
  14.     }
  15. }
public static void setCreditInfoStatus(CreditInfo info, CreditType type, CreditValidateStatus status) {
    ...

    Field[] fields = CreditInfo.class.getDeclaredFields();

    for (Field f : fields) {
        if (f.isAnnotationPresent(Credit.class) && f.getAnnotation(Credit.class).value() == type) {
            PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(CreditInfo.class, f.getName());
            if (pd != null)  {
                ...
            }
            break;
        }
    }
}

原先第7行写为 info.getClass(),乍一看与现有的代码功能上是一样的,但是别忘了让人又恨又爱的动态代理!上面代码返回的是真正的CreditInfo class,而左边的返回的是动态代理后的class,即意味着,第一个“if”永远返回的是false,除非动态代理后的对象的field上附带了原有的annotation

经验二:spring的声明式事务管理确很强大,强大到可以支持多线程,但是,结合上一点,不要在线程中调用this中的事务方法

声明式事务,即spring中使用aop织入或 @Transactional标记的方法注入事务容器,码农们可以完全不用操心何时begin,何时commit,何时 rollback,有没有嵌套,绝对傻瓜级的编程模型。但是,牢记,spring中的aop、annotation都是使用动态代理实现的,即,如果没有经过动态代理便也没有了事务管理,代码片段:

  1. public class AutomatedService{
  2.     ...
  3.  
  4.     loanQueue.execute(new Runnable() {
  5.  
  6.         @Override
  7.         public void run() {
  8.             Thread thread =  Thread.currentThread();
  9.  
  10.             while (!thread.isInterrupted()) {
  11.                 try {
  12.                     loanService.checkNSetLoanStatus();
  13.  
  14.                     Thread.sleep(loanStatusCheckIntervalMinutes * Consts.ONE_MINUTE);
  15.                 } catch (InterruptedException ex) {
  16.                     thread.interrupt();
  17.                 }
  18.             }
  19.         }
  20.     });
  21.  
  22.     ...
  23. }
public class AutomatedService{
    ...

    loanQueue.execute(new Runnable() {

        @Override
        public void run() {
            Thread thread =  Thread.currentThread();

            while (!thread.isInterrupted()) {
                try {
                    loanService.checkNSetLoanStatus();

                    Thread.sleep(loanStatusCheckIntervalMinutes * Consts.ONE_MINUTE);
                } catch (InterruptedException ex) {
                    thread.interrupt();
                }
            }
        }
    });

    ...
}

原先的checkNSetLoanStatus方法是定义在AutomatedService中的,且标记了@Transactional。 但是,令人发指的是,checkNSetLoanStatus中的事务没有被提交。在痛定思痛仔细回想了spring的声明式事务的本质后,豁然发现当调用this.checkNSetLoanStatus()时,并没有被织入事务管理。spring还没有霸道到或者说聪明到对this进行动态代理,于是将该方法移至其它service并注入,问题解决

原创内容,转载请注明: 转载自拈花微笑

本文链接地址: Spring之经验教训(一)

685

One comment

  • 2010 年 07 月 20 日 - 下午 2:29 | Permalink
    GD Star Rating
    loading...

    学习了,管用

  • 发表评论

    电子邮件地址不会被公开。 必填项已用 * 标注

    *

    您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" extra="">

    :wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!:

    使用新浪微博登陆

    无觅相关文章插件,快速提升流量