如何使用Java插装应用编程接口实施大小约束(在Infinispan中)


Infinispan不提供现成的大小限制,就像几乎所有其他标准缓存框架一样。您可以使用下面的Java工具应用编程接口来为您的使用Infinispan的产品或项目实施缓存大小约束。

1.在您的代码中引入插装应用编程接口

开发一个包含以下方法的类。一旦遇到这个方法,虚拟机将自动插入一个工具应用编程接口的实现。

 public class ServerInstrumentation {  
      private Instrumentation instrumentation = null;   
      private static final Logger LOGGER = Logger.getLogger(ServerInstrumentation.class);  
      private static ServerInstrumentation serverInstrumentation;  

      public static void premain(String args, Instrumentation pInstrumentation) {  
           serverInstrumentation = new ServerInstrumentation();  
           serverInstrumentation.instrumentation=pInstrumentation;  
      }  
      public static Instrumentation getInstance() {  
           return serverInstrumentation.instrumentation;  
      }  
}

您可以选择添加以下EJB(可选)使此对象在您的JEE应用程序中可用。从工具应用编程接口中重新实现您需要使用的方法。例如,在下面我们已经实现了sizeOf(),它实际上在内部调用Instrumentation.getObjectSize()

@Remote  
 public interface ServerInstrumentationInterface {  
      public long sizeOf(Object toBeSized);  
 }  
@Singleton  
 @Startup  
 public class ServerInstrumentationEJB implements ServerInstrumentationInterface {  
      private static Instrumentation instrumentation;  
      {  
           ClassLoader classLoader=this.getClass().getClassLoader().getParent();  
           try {  
                Class clazz = classLoader.loadClass(ServerInstrumentation.class.getName());  
                instrumentation=(Instrumentation)clazz.getDeclaredMethod("getInstance").invoke(null);                   
           } catch (Exception e) {  
                System.out.println("FFFFFF");  
           }  
      }  
      public long sizeOf(Object toBeSized) {  
           return instrumentation.getObjectSize(toBeSized);  
      }  
 }  

将此代码打包为agent.jar中包含以下内容MANIFEST.MF

Premain-Class: ServerInstrumentation  
 Agent-Class: ServerInstrumentation  

您应该将其放在正常部署位置(standalone\deployments)的野花,并提到它作为-javaagent服务器启动期间。以下内容应在野花里standalone.bat

 "%JAVA%" %JAVA_OPTS% "-javaagent:%JBOSS_HOME%\standalone\deployments\agent.jar" ^  
  "-Dorg.jboss.boot.log.file=%JBOSS_LOG_DIR%\server.log" ^  
  "-Dlogging.configuration=file:%JBOSS_CONFIG_DIR%/logging.properties" ^  
   -jar "%JBOSS_HOME%\jboss-modules.jar" ^  
   -mp "%JBOSS_MODULEPATH%" ^  
    org.jboss.as.standalone ^  
   "-Djboss.home.dir=%JBOSS_HOME%" ^  
    %SERVER_OPTS% 

最后,在您的JEE应用中,仪器方法可用于所有仪器目的。EJB将作为这一功能的门面。请确保您的中存在以下设置standalone.conf.bat

set "JAVA_OPTS=%JAVA_OPTS% -Djava.net.preferIPv4Stack=true -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Xbootclasspath/p:d:\wildfly\modules\system\layers\base\org\jboss\log4j\logmanager\main\log4j-jboss-logmanager-1.1.0.Final.jar;d:\wildfly\modules\system\layers\base\org\jboss\logmanager\main\jboss-logmanager-1.5.2.Final.jar" 
set "JAVA_OPTS=%JAVA_OPTS% -Djboss.modules.system.pkgs=org.jboss.byteman,org.jboss.logmanager"

2.在您的实际应用程序(客户端)中使用它

下面提供了使用规范执行方法的查找代码,如对象大小。除了缓存限制之外,这可能在您的JEE产品或解决方案中有多种用途。

// let's do the lookup           
ServerInstrumentationInterface cacheInstrumentationService = (ServerInstrumentationInterface)   
               initialContext.lookup("java:global/agent/" + ServerInstrumentationEJB.class.getSimpleName());  
cacheInstrumentationService.sizeOf(new String("Java and Infinispan Caching Innovation")));  

下列方法可以在不同的类中实现(CacheInstrumentation.java)在每次向缓存添加元素时执行以下功能,以检查是否超过了分配的大小。这将有上述EJB参考/实例封装在其中。

public boolean isEntityCacheLimitExceeded(Cache cache) {  
           boolean exceeded=false;  
           long currSize = cacheInstrumentationService.sizeOf(cache);  
           long allocSize = 10*1000*1024;  // 10 MB = 10 * 1000 * 1024 bytes
           if(currSize >= allocSize) {  
                exceeded=true;  
           }  
           return exceeded;  
}  

3.使用ConfigurationBuilder 引入约束

以下方法将用于setConfiguration(),这将有助于通知Infinispan配置已更改,以便它可以动态执行逐出。

public class CacheManagerUtilities {  
      public static Configuration setConfiguration(int maxNumberofEntries) {  
           return new ConfigurationBuilder().eviction().maxEntries(maxNumberofEntries)  
                     .strategy(EvictionStrategy.valueOf("LIRS")).expiration()  
                     .lifespan(2000)  
                     .wakeUpInterval(500)  
                     .maxIdle(1000).build();  
      }  
 } 

4.使用驱逐管理器请求和强制驱逐

每次在缓存中放入或添加元素时,您都可以使用sizeOf()检查是否超出了尺寸限制。如果是,则动态更改配置,将最大条目限制为当前存在的最大条目。我们现在将依靠Infinispan的驱逐算法来发挥作用,完成它的职责。

public void put(K key, V value) {            
           while (true) {  
                if (!cacheInstrumentation.isEntityCacheLimitExceeded(cache)) {  
                     cache.put(key, value);  
                     break;  
                } else {  
                     // set the configuration to the infinispan cache programmatically  
                     Configuration configuration = CacheManagerUtilities.setConfiguration(cache.size());  
                     cache.getCacheManager().defineConfiguration(cache.getName(), configuration);  

                     // start eviction manually  
                     EvictionManager evictionManager = cache.getAdvancedCache().getEvictionManager();  
                     evictionManager.processEviction();  

                     // set the configuration to the infinispan cache programmatically - large number such as 9999  
                     configuration = CacheManagerUtilities.setConfiguration(9999);  
                     cache.getCacheManager().defineConfiguration(cache.getName(), configuration);  
                }  
           }  
}

上面通常执行三件事:

  1. 使所有达到过期时间的元素过期(数据容器)。

  2. 使所有达到到期时间的元素到期(缓存存储)。

  3. 根据驱逐策略删除所有元素(删减至最大条目数)

您也可以使用Arquillian测试上述内容,通过在符合LIRS、LRU和大小约束的测试用例中创建数据来测试驱逐是否有效。

请注意,上面的代码还将确保只允许缓存可序列化的对象。它适用于所有需要将大小作为缓存约束机制的Java/JEE产品和解决方案。

快乐缓存!