<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>liangwj72</title>
    <description>广州优易数码科技有限公司</description>
    <link>http://liangwj72.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>最简单的LRU算法实现，线程安全的</title>
        <author>liangwj72</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liangwj72.javaeye.com">liangwj72</a>&nbsp;
          链接：<a href="http://liangwj72.javaeye.com/blog/123856" style="color:red;">http://liangwj72.javaeye.com/blog/123856</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          LRU算法用途之广就不说了，凡是要用cache的地方都可以见到它的身影。特别是线程多，并发高，数据量大的环境下。<br /><br />jdk1.5真好，在LinkedHashMap.java的源码中直接有这样的字样、“This kind of map is well-suited to building LRU caches.......The removeEldestEntry(Map.Entry) method may be overridden to impose a policy for removing stale mappings automatically when new mappings are added to the map.” 就是说自己写一下removeEldestEntry就搞定了。难为我当年自己写了一个。<br /><br />以下是代码，我增加的是线程安全的代码<br /><pre name="code" class="java">
import java.util.LinkedHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LRULinkedHashMap&lt;K, V> extends LinkedHashMap&lt;K, V>
{
    private final int maxCapacity;
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
    private final Lock lock = new ReentrantLock();

    public LRULinkedHashMap(int maxCapacity)
    {
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry&lt;K, V> eldest)
    {
        return size() > maxCapacity;
    }

    @Override
    public V get(Object key)
    {
        try {
            lock.lock();
            return super.get(key);
        }
        finally {
            lock.unlock();
        }
    }

    @Override
    public V put(K key, V value)
    {
        try {
            lock.lock();
            return super.put(key, value);
        }
        finally {
            lock.unlock();
        }
    }
}
</pre><br />注意，只有get和put是线程安全的。<br /><br />本来这贴是想放到入门论坛的，不过想了一下，要用LRU算法的，知道ReentrantLock的人好像也不能算新手了。
          <br/>
          <span style="color:red;">
            <a href="http://liangwj72.javaeye.com/blog/123856#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Sep 2007 16:51:24 +0800</pubDate>
        <link>http://liangwj72.javaeye.com/blog/123856</link>
        <guid>http://liangwj72.javaeye.com/blog/123856</guid>
      </item>
      <item>
        <title>Spring + JMX 入门</title>
        <author>liangwj72</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liangwj72.javaeye.com">liangwj72</a>&nbsp;
          链接：<a href="http://liangwj72.javaeye.com/blog/123842" style="color:red;">http://liangwj72.javaeye.com/blog/123842</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          这篇文章主要是结合实际应用的情况对Spring开发参考手册20章的补充，提供一些建议给刚接触JMX的开发人员，让大家更轻松的使用JMX。<br /><br /><span style="font-size: 18pt"><span style="color: blue">1.连接器</span></span><br />参考手册中介绍了无数连接器，包括rmi/iiop/Burlap/Hessian/SOAP等等，非常的多。但实际上，我们用得上的并不多。最容易配的是rmi，转帖参考手册中的例子：<br /><pre name="code" class="java">
&lt;bean id="serverConnector"
      class="org.springframework.jmx.support.ConnectorServerFactoryBean">
  &lt;property name="objectName" value="connector:name=rmi"/>
  &lt;property name="serviceUrl" 
            value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector"/>
&lt;/bean>
</pre><br />这种方式配起来最简单，不需要任何附加的库。用起来也不麻烦，在命令行运行jconsole，然后输入上面的serviceUrl就可以了。<br /><br />这是最容易配的，但不是最好用的。因为程序开发出来后，程序的监控/管理界面一般是由业务人员或者客户来使用，并不是程序员在使用，他们的机器上很少装有jdk，没jconsole可用；还有一个缺点就是serviceUrl未免太长了，非常不容易记。很多时候程序员自己都不记得，就更别说其他人了。<br /><br />最简单的最好用的还是通过IE就可以查看和管理了，这里我推荐mx4j，这个工具包提供了一个http的管理界面，非常好用。下载：<a href="http://jaist.dl.sourceforge.net/sourceforge/mx4j/mx4j-3.0.2.zip" target="_blank">http://jaist.dl.sourceforge.net/sourceforge/mx4j/mx4j-3.0.2.zip</a>。以下是最简版的使用mx4j的配置：<br /><pre name="code" class="java">
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
&lt;beans>
	&lt;!-- MBeanExporter -->
	&lt;bean id="exporter"
		class="org.springframework.jmx.export.MBeanExporter"
		depends-on="mbeanServer">
		&lt;property name="beans">
			&lt;map>
				&lt;entry key="JmxTest:name=RuntimeInfo"
					value-ref="managerRuntime" />
				&lt;entry key="MX4J:name=HttpAdaptor"
					value-ref="httpAdaptor" />
			&lt;/map>
		&lt;/property>
		&lt;property name="server" ref="mbeanServer" />
		&lt;property name="assembler">
			&lt;bean id="assembler"
				class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
				&lt;property name="attributeSource">
					&lt;bean id="attributeSource"
						class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
				&lt;/property>
			&lt;/bean>
		&lt;/property>
	&lt;/bean>
	&lt;!-- MBeanServerFactoryBean -->
	&lt;bean id="mbeanServer"
		class="org.springframework.jmx.support.MBeanServerFactoryBean">
	&lt;/bean>

	&lt;!-- HttpAdaptor & XSLTProcessor -->
	&lt;bean id="httpAdaptor"
		class="mx4j.tools.adaptor.http.HttpAdaptor">
		&lt;property name="processor">
			&lt;!-- XSLTProcessor -->
			&lt;bean id="xsltProcessor"
				class="mx4j.tools.adaptor.http.XSLTProcessor" />
		&lt;/property>
		&lt;property name="port" value="7788" />
	&lt;/bean>
	&lt;bean id="managerRuntime"
		class="jmxTest.mbean.ManagerRuntimeMBean">
	&lt;/bean>
&lt;/beans>
</pre><br />这几乎是无法在精简的配置了。里面的managerRuntime是样例的mbean。<br /><br /><span style="font-size: 18pt"><span style="color: blue">2.MBeanInfoAssembler</span></span><br />这个接口的用途是将你所需要变成MBean类的信息提取出来，并生成MBean。Spring大大简化了MBean的实现方式，我们现在已经不需要自己实现MBean接口定义的方法了。在参考手册中介绍了好几种MBeanInfoAssembler接口，我们在网上常见的例子就是SimpleReflectiveMBeanInfoAssembler，这个接口通过反射的方法提取出我们要管理的类的信息，包括里面有什么方法啊，各个方法有什么参数啊，等等。<br /><br />这个接口真简单，我们什么都不用管了，但实际使用的时候，我们发现一些问题：<br />a. 我们无法为每个方法加注释，以及帮这个MBean加注释，管理界面都是一堆方法名，业务人员经常过来东问西问，真麻烦。<br />b. 反射时把类的所有方法都找了出来，甚至连用于spring 注入的setter，getter等完全不搭边界的东西也暴露出来，以至于管理界面上有N多的方法，眼都花。<br /><br />本人强烈推荐用AnnotationJmxAttributeSource，看到Annotation字样，大家也就知道是用jdk1.5的Annotation了。确实如此，我们可以非常方便的用Annotation加注释，并限制某些方法不要暴露出去。参考手册上有详细的例子，我下面给的例子则是简化版：<br /><br /><span style="color: brown">jmxTest/mbean/ManagerRuntimeMBean.java</span><pre name="code" class="java">
package jmxTest.mbean;

import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource(description = "VM运行状态")
public class ManagerRuntimeMBean {

    private long getMax() {
        return Runtime.getRuntime().maxMemory() >> 20;
    }

    private long getTotal() {
        return Runtime.getRuntime().totalMemory() >> 20;
    }

    private long getFree() {
        return Runtime.getRuntime().freeMemory() >> 20;
    }

    private long getUsed() {
        return getTotal() - getFree();
    }

    @ManagedAttribute(description = "可分配的最大内存")
    public String getMaxMemory() {
        return getMax() + " M";
    }

    @ManagedAttribute(description = "已分配内存")
    public String getTotalMemory() {
        return getTotal() + " M";
    }

    @ManagedAttribute(description = "已使用内存")
    public String getUsedMemory() {
        return getUsed() + " M";
    }

    @ManagedOperation(description = "Shutdown VM")
    public void shutdown() {
        Runtime.getRuntime().exit(0);
    }
}
</pre><br />和参考手册上例子不同地方在于，我们只使用@ManagedResource这些注释中最简单的功能，而不是参考手册上非常长的一大段。<br /><br />上面例子中没有加@ManagedAttribute的那几个方法不会被暴露出去。下面的例子则是对方法参数加说明的例子<br /><span style="color: brown">jmxText/mbean/Mbean1.java</span><br /><pre name="code" class="java">
package jmxTest.mbean;

import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource(description = "mbean1")
public class Mbean1 {
    private String p1;

    @ManagedAttribute
    public String getP1() {
        return p1;
    }

    @ManagedOperation(description="方法P1 的说明")
    @ManagedOperationParameters({
        @ManagedOperationParameter(name = "p1", description = "参数 p1 的说明")})
    public void addP1(String p1) {
        this.p1 = p1;
    }
}
</pre><br /><br /><span style="font-size: 18pt"><span style="color: blue">3.启动</span></span><br />最后一个程序则是启动程序，我们让系统跑起来<br /><span style="color: brown">JmxTestStart.java</span><br /><pre name="code" class="java">
package jmxTest;

import java.io.IOException;

import javax.management.MalformedObjectNameException;

import jmxTest.mbean.Mbean1;
import mx4j.tools.adaptor.http.HttpAdaptor;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.support.ObjectNameManager;

public class JmxTestStart {
    public static void main(String[] args)
            throws IOException,
                MalformedObjectNameException, Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                new String[] { "beanRefJMXServer.xml", });

        //启动 HttpAdaptor，mx4j的HttpAdaptor真讨厌，要手工启动
        HttpAdaptor httpAdaptor = (HttpAdaptor)ctx.getBean("httpAdaptor");
        httpAdaptor.start();

        //动态注册一个MBean的例子
        MBeanExporter exporter = (MBeanExporter) ctx.getBean("exporter");
        exporter.registerManagedResource(new Mbean1(),
                ObjectNameManager.getInstance("ZtManager:name=mbean"));
    }
}
</pre><br />注意，这个启动程序还有一个特别之处，第一个例子ManagerRuntimeMBean是在配置文件中说明要变成MBean的，第二个例子Mbean1则是在系统运行时动态注册的。
          <br/>
          <span style="color:red;">
            <a href="http://liangwj72.javaeye.com/blog/123842#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Sep 2007 16:12:48 +0800</pubDate>
        <link>http://liangwj72.javaeye.com/blog/123842</link>
        <guid>http://liangwj72.javaeye.com/blog/123842</guid>
      </item>
  </channel>
</rss>