工作经验总结1

 

  1. 在 MySQL 中,只有 Timestamp 类型带有时区信息,所以在分布式系统中要尽量使用 Timestamp 类型,否则会造成因时区不同导致的时间不一致。
  2. OSGi Service (OSGi Service,也成为 Blueprint,源自 Spring OSGi Service 技术)。在使用中主要涉及这两个配置项 <osgi:service /> 服务提供者和 <osgi:reference /> 服务使用者。
    • <osgi:service />
      注册一个 OSGi Service 非常简单,用下面的配置即可。(当然一个 service 也可以注册在多个 interface 上,具体写法可参考文档)
      <service ref="beanToPublish"interface="com.xyz.MessageService"/>

      service 配置中还有几个属性简单介绍下 id, scope, ranking。<osgi:service /> 实际是一个 org.osgi.framework.ServiceRegistration 的元素,如果你需要引用它的话可以使用 id 里的值;scope 如果为 bundle 的话,那每个使用这个 service 的 bundle 都会有一个独立的引用;ranking 用于如果一个 interface 有多个 service 的话,哪个 service 被优先引用。
    • <osgi:reference />
      引用一个 OSGi Service 可使用一下配置。同样,可以用多个 interfaces 上的 service。
      <reference id="messageService"interface="com.xyz.MessageService"/>

      reference 中有个属性需要注意“cardinality ”,它用于表示引用的 OSGi Service 是否总是必须的。默认值是 1..1,意思是指定的 OSGi Service 必须总是可用的。如果你想让你引用 OSGi Service 的 bundle 在没有匹配 Service 的时候仍能启动,必须将 cardinality 改为 0..1 或 0..N。

  3. MySQL Concurrent Performance
    MySQL 的性能问题在并发系统中很容易出现,一个更严重的问题是 "Lock time out, restart transaction" 这样的异常。下面具体解释下:
    • 对于可能存在的对同一条记录的并发 update 操作,可用异步的方式解决,当然这需要很多的逻辑修改的工作。因为是对同一条记录的操作,所以可以用算法消除一些多余的 update 操作。
    • 对于频繁的并发 select 操作,可用缓存等方式解决。但在分布式系统中,需要考虑的是如何同步各个 JVM 缓存中的数据。一个可选的技术是 Terracotta,之后我会具体介绍。

  4. MySQL 子查询的问题
    update ClusterInstance
        set isMaster = 1, replicationTimestamp = unix_timestamp()
    where
        (
            select count(*) from (select tmp.* from ClusterInstance tmp where siteId = #siteId#) a
            where a.isMaster = 1 and TIMESTAMPDIFF(SECOND, a.refreshTimestamp, now())
                <![CDATA[ < ]]> #interval2Times#
        ) = 0
        and
        (
            select a.instanceId from (select tmp.* from ClusterInstance tmp where siteId = #siteId#) a
            where
                TIMESTAMPDIFF(SECOND, a.refreshTimestamp, now()) <![CDATA[ < ]]> #interval2Times#
            order by a.instanceId asc limit 1
        ) = instanceId
        and instanceId = #instanceId#

    从上面的的语句可以看出,这一句“select tmp.* from ClusterInstance tmp wheresiteId = #siteId#”是必须的。这是 MySQL 子查询的一个问题。

  5. Apache Camel 的 send* 和 request* 方法
    说实话,Camel 的诸多 send 和 request 方法至今我也没完全搞明白。简而言之,如果你在用的时候有解决不了的问题的时候,换一个方法试试吧。

  6. ConcurrentHashMap
    ConcurrentHashMap 的默认并发级别是16,有时会不够用,那就用带参数的构造器吧。

  7. JAXB
    如果用 JAXB 解析的 XML 前后有空行或空格的话,那会报出 "... [xX]... not allowed..." 的异常。

  8. Spring 事务
    众所周知,在 Spring 中有两种方式为方法添加数据库事务支持。一种是编程方式,另一种是配置方式。后者又可分为 XML 配置和 Annotation 两种方式。对于配置式的事务支持我不想多说,文档描述的很详细。需要注意的是,默认情况下事务回滚只发生在抛出异常时,对于需要在更复杂条件下回滚的情况,那就要使用编程方式的事务支持了。

    transactionTemplate .execute( new  TransactionCallback() {
        @Override
         public  Object doInTransaction(TransactionStatus transactionStatus) {
            ....
             // Mark rollback
            transactionStatus.setRollbackOnly();
            ....
        }
    }

  9. Class Loader 问题
    在 OSGi 环境中最常见的一类问题就是 classloader 问题。下面逐一描述(以下问题都是在 ServiceMix 中出现的):
    1. Spring ORM 的 SqlMapClientFactoryBean 无法找到 iBatis 配置文件的问题:这个错误发生在 SqlMapClientFactoryBean  的 buildSqlMapClient 方法中,原因是 Spring 的 Resource 类使用 Classloader 的 getInputStream 方法寻找资源,但是在 ServiceMix 中,此时的 classloader 是 OSGi 相关的,结果是以 ServiceMix 的跟目录寻找文件,但是真正的配置文件缺失放在 bundle jar 文件中。解决方法是在加载配置文件的代码前后加上如下的代码:

      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
      // Load and parse iBatis configuration files.
      Thread.currentThread().setContextClassLoader(loader);

    2. 由 Classloader 导致的 JAXB 错误
      如果在 SerivceMix 中使用 JAXB 解析 XML,你可能会遇见下面的异常:

      Caused by: javax.xml.bind.JAXBException: Unable to create context
      - with linked exception:
      [java.lang.NoSuchMethodException: com.sun.xml.bind.v2.ContextFactory.createContext(java.lang.String, java.lang.ClassLoader)]
              at javax.xml.bind.ContextFinder.find(ContextFinder.java:72)
              at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:77)
              at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:73)
              at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:69)
              at com.alcatel_lucent.aes.scf.configurator.interceptor.TdrInterceptor.<init>(TdrInterceptor.java:77)
              at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
              at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
              at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
              at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
              at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:100)
              ... 67 more
      Caused by: java.lang.NoSuchMethodException: com.sun.xml.bind.v2.ContextFactory.createContext(java.lang.String, java.lang.ClassLoader)
              at java.lang.Class.getMethod(Class.java:1605)
              at javax.xml.bind.ContextFinder.find(ContextFinder.java:69)
              ... 76 more


      这是由于 jaxb-impl.jar 并不是个 OSGi aware 的 jar 包,所以在 OSGi 环境中,如果 classloader 不合适的话,很容易产生一些奇怪的问题。具体到这个问题,如果不加特殊的处理,Bundle 所使用的 classloader 是 org.springframework.osgi.util.BundleDelegatingClassLoader。使用这个 classloader 和 JAXB 时,就有可能会出现上面异常。解决方法是使用以下代码使用 JAXB:

      ClassLoader cl = com.alcatel_lucent.aes.scf.configurator.
          ObjectFactory. class .getClassLoader();
      JAXBContext jaxbContext = JAXBContext.
              newInstance( "com.alcatel_lucent.aes.scf.configurator" , cl);

      此时的 classloader 是 org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader,能够正确加载 JAXB 的 jar 包。


    3. 在 ServiceMix 中使用 CXF 时,如果遇到类加载的奇怪问题,也是由于 classloader issue。解决方法是

      ClassLoader ocl = Thread.currentThread().getContextClassLoader();
      try  {            
          Thread.currentThread().setContextClassLoader(getClass().
                  getClassLoader());
          reallyDoSomething(arg);
      }  finally  {
          Thread.currentThread().setContextClassLoader(ocl);
      }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值