侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

深入理解Ehcache系列(四)

2022-06-30 星期四 / 0 评论 / 0 点赞 / 56 阅读 / 17407 字

在系列三中我们介绍了可以通过配置文件或者参数传递来配置Ehcache的系统参数。但是如果我们想动态的去调整这些参数应该怎么办呢? 这是完全可行的,Cache提供了相应的方法。 Cache ca

      在系列三中我们介绍了可以通过配置文件或者参数传递来配置Ehcache的系统参数。但是如果我们想动态的去调整这些参数应该怎么办呢?

      这是完全可行的,Cache提供了相应的方法。


Cache cache = manager.getCache("sampleCache");
CacheConfiguration config = cache.getCacheConfiguration();
config
.setTimeToIdleSeconds(60);
config
.setTimeToLiveSeconds(120);
config
.setmaxEntriesLocalHeap(10000);
config
.setmaxEntriesLocalDisk(1000000);


/**     * @param propertyName     * @param oldValue     * @param newValue     */    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {      PropertyChangeSupport pcs;      synchronized (this) {        pcs = propertyChangeSupport;      }      if (pcs != null && (oldValue != null || newValue != null)) {        pcs.firePropertyChange(propertyName, oldValue, newValue);      }    }



       先让我们来回忆一下PropertyChangeSupport的具体用法。


PropertyChangeSupport类的官方文档解释:
     

This is a utility class that can be used by beans that support bound properties.  You can use an instance of this class as a member field of your bean and delegate various work to it.



     关联属性,也称绑定属性。当绑定属性值发生变化时,通知所有相关的监听器。为了实现属性绑定,必须实现两个机制。


  1. 只要属性的值发生变化,该bean发送一个PropertyChange事件给所有已注册的监听器。该变化可以发生在调用set方法时,或者程序的用户做出某种动作时。

  2. 为了使感兴趣的监听器能够进行注册,bean必须实现以下两个方法:



void addPropertyChangeListener(PropertyChangeListener listener);void removePropertyChangeListener(PropertyChangeListener listener);

    通过java.bean包下的PropertyChangeSupport类来管理监听器。要使用这个类,bean必须有一个此类的数据域。



private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);


    /**     * @param listener     */    public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {      if (listener != null && propertyChangeSupport != null) {        propertyChangeSupport.removePropertyChangeListener(listener);        propertyChangeSupport.addPropertyChangeListener(listener);      }    }    /**     * @param listener     */    public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {      if (listener != null && propertyChangeSupport != null) {        propertyChangeSupport.removePropertyChangeListener(listener);      }    }



    bean的属性发生变化时,使用PropertyChangeSupport对象的firePropertyChange方法,它会将一个事件发送给所有已经注册的监听器。该方法有三个参数:属性的名字、旧的值以及新的值。属性的值必须是对象,如果是简单数据类型,则必须进行包装。

    /**     * @param propertyName     * @param oldValue     * @param newValue     */    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {      PropertyChangeSupport pcs;      synchronized (this) {        pcs = propertyChangeSupport;      }      if (pcs != null && (oldValue != null || newValue != null)) {        pcs.firePropertyChange(propertyName, oldValue, newValue);      }    }


所有注册的监听器实现PropertyChangeListener接口,该接口中有一个方法。


public class RuntimeCfg implements PropertyChangeListener {     //部分代码省略        /**         * Handles changes to the Configuration this RuntimeCfg backs         * @param evt the PropertyChangeEvent         */        public void propertyChange(final PropertyChangeEvent evt) {            try {                DynamicProperty.valueOf(evt.getPropertyName()).applyChange(evt, this);            } catch (IllegalArgumentException e) {                throw new IllegalStateException(evt.getPropertyName() + " can't be changed dynamically");            }        }}

   再来看看DynamicProperty做了什么。

/**     * Enum of all properties that can change once the Configuration is being used by a CacheManager     */    private static enum DynamicProperty {        cacheManagerName {            @Override            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {                config.cacheManagerName = (String) evt.getNewValue();            }        },        defaultCacheConfiguration {            @Override            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {                LOG.debug("Default Cache Configuration has changed, previously created caches remain untouched");            }        },        maxBytesLocalHeap {            @Override            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {                ArrayList<ConfigError> errors = new ArrayList<ConfigError>();                Long newValue = (Long)evt.getNewValue();                if ((Long) evt.getOldValue() > (Long) evt.getNewValue()) {                    // Double check for over-allocation again                    for (Cache cache : getAllActiveCaches(config.cacheManager)) {                        CacheConfiguration cacheConfiguration = cache.getCacheConfiguration();                        errors.addAll(cacheConfiguration.validateCachePools(config.getConfiguration()));                        errors.addAll(cacheConfiguration.verifyPoolAllocationsBeforeAddingTo(config.cacheManager,                            newValue, config.getConfiguration().getMaxBytesLocalOffHeap(), config.getConfiguration().getMaxBytesLocalDisk(), null));                    }                }                if (!errors.isEmpty()) {                    throw new InvalidConfigurationException("Can't reduce CacheManager byte tuning by so much", errors);                }                // Recalculate % based caches                long cacheAllocated = 0;                for (Cache cache : getAllActiveCaches(config.cacheManager)) {                    cache.getCacheConfiguration().configCachePools(config.getConfiguration());                    long bytesLocalHeap = cache.getCacheConfiguration().getMaxBytesLocalHeap();                    cacheAllocated += bytesLocalHeap;                }                config.cacheManager.getOnHeapPool().setMaxSize(newValue - cacheAllocated);            }        },        maxBytesLocalDisk {            @Override            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {                if ((Long)evt.getOldValue() > (Long)evt.getNewValue()) {                    // Double check for over-allocation again                    for (CacheConfiguration cacheConfiguration : config.getConfiguration().getCacheConfigurations().values()) {                        cacheConfiguration.isMaxBytesLocalDiskPercentageSet();                    }                }                config.cacheManager.getOnDiskPool().setMaxSize((Long) evt.getNewValue());                // Recalculate % based caches ?            }        };        abstract void applyChange(PropertyChangeEvent evt, RuntimeCfg config);    }



    使用这个类管理监听器的好处是,它是线程安全的。如果使用一个循环体来set Bean的属性,则这个类可以保证所有监听器执行触发事件的有序。 还有一个好处是,这个类支持 fire 带索引的属性改变事件(详见 java.bean.IndexedPropertyChangeEvent )。此时向注册的监听器发送一个 PropertyChangeEvent 的方法为:

void fireIndexedPropertyChange(String PropertyName,int index,Object oldValue,Object newValue);




广告 广告

评论区