spring中cache服务的实现(一)

cache服务的实现(在spring中)

 

扩展Spring:实现Cache服务- -

                                      

 

 

TargetSource的概念

       Spring Framework引入了TargetSource的概念,使用org.springframework.aop.TargetSource接口来表示。它负责返回实现了JointPoint的"target object"。当AOP proxy处理一个方法调用时,TargetSource的实现返回target对象的实例。

       使用Spring AOP的开发人员通常并不需要直接和TargetSource打交道,但TargetSource提供了支持pooling,hot swappable等高级特性。例如,pooling TargetSource使用一个pool管理对象实例,为每次调用返回不同的target实例。

       如果你不指定TargetSource,Spring AOP将使用一个缺省的实现来包装对象,并且每次调用都会返回同一个对象实例。

 

我的目标

       Spring Framework使用TargetSource的概念实现了pooling的功能,其中使用了Jakarta的Commons Pool。通过编写配置文件声明,Spring可以pooling任何一个POJO对象。我的目标是模仿pooling的实现方式,实现一个简单的缓存机制。用于探索Spring AOP的实现方式,以便扩展目前Spring Framework没有实现的功能。

 

选择对象缓存类库

       目前,开源的对象缓存类库有很多,如Jakarta Commons Cache,OSCache,Java Caching System和Java Object Cache等。其中OSCache的比较成熟,应用较广(如Hibernate,iBatis等),功能也很强大(支持Cluster)。因此,我选择了OSCache作为实现Cache TargetSource的类库。

 

准备测试用例

       考虑一下这样的应用情景,我的应用需要一个管理数据的对象,该对象每隔一定的时间从数据库中读取数据,并缓存在内存中。在缓存期间,如果客户程序读取数据,该数据对象将返回内存中的数据,如果数据超过指定的缓存时间,则重新从数据库中读取并更新数据。

       首先,我模仿CommonsPoolTargetSource编写了以下的testcache.xml配置文件:

 

<beans>

     <bean id="businessObjectTarget" class="unittest.MyBusinessObject" singleton="false"/>

     <bean id="cacheTargetSource" class="unittest.OSCacheTargetSource">

         <property name="target"><ref local="businessObjectTarget"/></property>

         <property name="refreshPeriod"><value>10</value></property>

     </bean>

     <bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">

         <property name="proxyInterfaces"><value>unittest.Business</value></property>

         <property name="targetSource"><ref local="cacheTargetSource"/></property>

     </bean>

</beans>

 

        然后,编写测试用例CacheTargetSourceTest:

 

public class CacheTargetSourceTest extends TestCase {

      ApplicationContext ctx = null;

      BizManager manager;

 

      protected void setUp() throws Exception {

          super.setUp();

          ctx = new FileSystemXmlApplicationContext("testcache.xml");

          manager = new BizManager(200);

          manager.start();

      }

 

     public void testGetId() throws Exception {

         for (int i=0; i<6; i++) {

              Thread.sleep(2000);

              Business biz = (Business)ctx.getBean("businessObject");

              assertNotNull(biz);

              System.out.println("get id from BizObjec=" + biz.getId());

         }

     }

}

 

       接下来,编写业务测试代码Business,MyBusinessObject:

public interface Business {

      public int getId();

}

 

public class MyBusinessObject implements Business {

     final Log logger = LogFactory.getLog(this.getClass());

     private int id = 0;

 

     public MyBusinessObject() {

          logger.debug("create new MyBusnissObject");

          id = BizManager.getId();

     }

 

     public int getId() {

          return id;

     }

}

 

     其中MyBusinessObject通过一个BizManager线程类来更新数据库,模拟数据库中的数据更新。

 

public class BizManager extends Thread {

      private int period = 1000;

      private static int id = 0;

 

      public BizManager(int l) {

          this.period = l;

      }

 

      public void run() {

          System.out.println("BizManager started.");

          try {

              while (true) {

                  sleep(period);

                  id++;

              }

         } catch(Exception ex) {}

      }

      public static int getId() {

           return id;

      }

}

 

       最后,实现一个简单OSCacheTargetSource类。我在这里试探性地实现了TargetSource接口,并通过setRefreshPeriod方法指定了更新数据的时间间隔。在这里有一些地方需要说明。为了能让FactoryBean生成新的TargetSource实例,TargetSource的isStatic方法返回false;在releaseTarget方法中调用CacheAdministrator的destroy方法;每次更新内存的数据时,都生成新的数据管理对象,以调用构造器中读取更新数据的方法,这种做法当然很不优雅,留待以后重构。代码如下:

 

public class OSCacheTargetSource implements TargetSource {

       private int refreshPeriod = 2000;

       private Object target;

       private final static String MY_KEY = "mykey";

       private GeneralCacheAdministrator admin;

       private final Log logger = LogFactory.getLog(OSCacheTargetSource.class);

 

       public OSCacheTargetSource() {

             admin = new GeneralCacheAdministrator();

       }

 

       public boolean isStatic() {

             return false;

       }

 

       public void setTarget(Object obj) {

             this.target = obj;

       }

 

       public void releaseTarget(Object target) throws Exception {

            admin.destroy();

       }

 

       public int getRefreshPeriod() {

            return refreshPeriod;

       }

 

       public void setRefreshPeriod(int i) {

            refreshPeriod = i;

       }

 

       private Object getCached() {

           try {

                 //CacheEntry.INDEFINITE_EXPIRY = -1

                 target = (Object) admin.getFromCache(MY_KEY, refreshPeriod);

           } catch (NeedsRefreshException nre) {

                 try {

                       target = target.getClass().newInstance();

                       admin.putInCache(MY_KEY, target);

                 } catch (Exception ex) {

                      target = nre.getCacheContent();

                      admin.cancelUpdate(MY_KEY);

                 }

          }

          return target;

      }

 

      public Object getTarget() throws Exception {

            return getCached();

      }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值