接下来分析extend包:          
JsonBinder类: 主要是使用Jackson来完成json <-> java object 工具封装.
写了一个简单的小main测试了一把:
public static void main(String[] args) {
  JsonBinder binder = new JsonBinder();
  Point p = new Point();
  p.setX(1);
  p.setY(2);
  String jsonStr = binder.toJson(p);
  System.out.println(jsonStr);

  Point t = binder.fromJson(jsonStr, Point.class);
  System.out.println(t.getX());
  System.out.println(t.getY());
 }        
 //结果:
{"x":1,"y":2}
1
2


必须注意点是, Point不是java.awt的类, 因为这个类没有实现Serializable接口.

JaxbBinder是使用Jaxb来完成 xml <-> java object 的工具:             


一段小小的测试代码:
@XmlRootElement(name = "point")
public class Point implements Serializable {
 
 private static final long serialVersionUID = 1L;
 private int x;
 private int y;

 @XmlElement(name = "x")
 public int getX() {
  return x;
 }
 public void setX(int x) {
  this.x = x;
 }
 @XmlElement(name = "y")
 public int getY() {
  return y;
 }
 public void setY(int y) {
  this.y = y;
 }
}
//注意: 这里面的@XmlElement(name = "x")不能加在字段上, 否则会抛异常!

public static void main(String[] args) {
  JaxbBinder binder = new JaxbBinder(Point.class);
  Point p1 = new Point();
  p1.setX(1);
  p1.setY(2);
  String xml1 = binder.toXml(p1);
  System.out.println(xml1);
 }
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<point>
    <x>1</x>
    <y>2</y>
</point>

这两个工具类很好用, 所以, 可以加到自己的代码库中.

再看memcached包下的类, 主要是一个测试用服务器, 一个客户端以及一个客户端工厂

JmemcachedServer类: JMemcached的封装, 主要用于功能测试.
@PostConstruct 构造函数完成后执行的方法
@PreDestroy 容器销毁之前执行的方法     

看看这个设计: 一个JmemcachedServer类就表示一个memcached服务器, 启动, 停止.

再看SpyMemcachedClientFactory类:
这明显是一个工厂类, 负责产生spy的客户端的.   
建立SpyMemcached Client池,负责初始化与关闭.
实现了2个接口: InitializingBean, DisposableBean ,
InitializingBean接口允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作 
DisposableBean接口允许一个bean.可以再包含它的BeanFactory销毁的时候得到一个回调。
                                                  
afterPropertiesSet()方法:
在这里面主要是做了一些客户端的设置, 比如一致性hash算法等.
最后初始化一个客户端, 放到一个List中.

destroy()方法:
就是把客户端池的客户端全部shutdown

SpyMemcachedClient类:
对SpyMemcached Client的二次封装,提供常用的Get/GetBulk/Set/Delete/Incr/Decr函数的封装.
//<T>: 表示新方法是一个泛型方法, 返回类型是T
public <T> T get(String key) {
  try {
   return (T) client.get(key);
  } catch (RuntimeException e) {
   logger.warn("Get from memcached server fail,key is" + key, e);
   return null;
  }
 }                                                  


再看security包下的类:
GMailEngine: JCaptcha验证码图片生成引擎,仿照JCaptcha2.0编写类似GMail验证码的样式.
JCaptchaFilter : 集成JCaptcha验证码的Filter.  
通过这个filter来学习一下filter的写法:
init方法: 通过web.xml文件中传来的参数来初始化参数.
// 在web环境中获取ApplicationContext的方法
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(fConfig.getServletContext());
doFilter方法的逻辑:
// 符合验证连接的则为验证, 并把验证结果返回
// 否则的话, 则产生图片, 并把图片写回到浏览器中
  if (StringUtils.indexOf(servletPath, filterProcessesUrl) == 0) {
   boolean validated = validateCaptchaChallenge(request);
   if (validated) {
    chain.doFilter(request, response);
   } else {
    redirectFailureUrl(request, response);
   }
  } else {
   genernateCaptchaImage(request, response);
  }

utils包中主要是加密算法, 详情参考测试case.

cxf包中应该是和webservice有关的cxf工具, 暂时不知道具体作用, TODO it.

queue包, 主要是Block queue的应用:
QueuesHolder类: BlockingQueue Map的持有者.负责产生一个block queue的.      
这个类里面的标记都是和JMX有关的.
@ManagedResource: 把 Class 所有的实例标记为由JMX管理的资源
@ManagedOperation: 把一个方法定义成jmx管理的方法
如果能够设计一个可以jmx管理的队列, 那么就可以动态的往队列里面增加数据.  

// 使用ConcurrentMap来作为阻塞队列的池, 注意是静态方法. 很典型的单例模式.
private static ConcurrentMap<String, BlockingQueue> queueMap 
                                                  
getQueue(String queueName)方法:
基本上就是如果池中存在, 则取出, 否则, 则创建.

再看 QueueConsumer类:
这个类实现了Runnable接口, 是单线程消费Queue中消息的任务基类. 定义了QueueConsumer的启动关闭流程.

start()方法: 被注解成@PostConstruct
逻辑:
queue = QueuesHolder.getQueue(queueName); // 取得队列的名字
if (persistence) {                        // 如果被持久化过的, 那么从文件中把数据读到队列中
   synchronized (persistenceLock) {
    restoreQueue();
   }
  }
//制造一个单线程的任务执行器, 其中使用的CustomizableThreadFactory类, 实现了java.util.concurrent.ThreadFactory
//这个接口定义了产生一个新的线程  
executor = Executors.newSingleThreadExecutor(new CustomizableThreadFactory("Queue Consumer-" + queueName));  
//执行器负责执行一个消费者动作, 这个消费者必须实现了Runnable接口
executor.execute(this);

其中restoreQueue函数, 演示了如何使用ObjectInputStream:
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
    int count = 0;
    while (true) {
     try {
      Object message = ois.readObject();
      queue.put(message);
      count++;
     } catch (EOFException e) {
      break;
     }
    }

看看这个基础类的两个子类:
这是一个典型的策略模式, 将具体的策略推迟到子类实现.

PeriodConsumer类: 采用定时批量读取Queue中消息策略的Consumer.
看一下主函数: 
//线程执行函数,定期批量获取消息并调用processMessageList()处理.
//sleep,wait,join这些方法内部会不断检查中断状态的值,如果发现线程的状态被置为已中断,
// sleep,wait,join这些方法便抛出InterruptedException异常。
//被中断的线程则将控制权交给catch语句,一些正常的逻辑要被放到catch中来运行。    
//interrupt()方法设置一个这样的标志。一旦这个标志被设置了,则所有当前正在阻塞的方法                        
//(限定在由于wait、sleep、join三种方法引发的阻塞)都会立刻完成“跳出阻塞状态、抛出InterruptedException异常、
// 清除中断状态标志”这三件工作。
public void run() {
  try {
   while (!Thread.currentThread().isInterrupted()) {
    List list = new ArrayList(batchSize);
    queue.drainTo(list, batchSize);
    processMessageList(list);
    if (!Thread.currentThread().isInterrupted()) {
     Thread.sleep(period);
    }
   }
  } catch (InterruptedException e) {
   // Ignore.
  } finally {
   //退出线程前调用清理函数.
   clean();
  }
 }
processMessageList方法是一个虚方法, 留待后续的实现类实现.

BlockingConsumer子类: 采用即时阻塞读取Queue中消息策略的Consumer.      
//这里应用了block queue的特性: 如果队列有数据, 则消费者消费
//如果队列没有数据, 则消费者阻塞, 等待消费
public void run() {
  //循环阻塞获取消息直到线程被中断.
  try {
   while (!Thread.currentThread().isInterrupted()) {
    Object message = queue.take();
    processMessage(message);
   }
  } catch (InterruptedException e) {
   // Ignore.
  } finally {
   //退出线程前调用清理函数.
   clean();
  }
 }      
 
最后看一下extend包中最后一个类:
JmxClientTemplate类:
----------------------------------------------------------------------
 * JMX客户端模板.
 *
 * 职责有:
 * 1.负责连接和关闭远程JMX Server,并持有连接.
 * 2.创建可操作远程MBean的本地MBean代理.
 * 3.按属性名直接读取或设置远程MBean属性(无MBean的Class文件时使用).
----------------------------------------------------------------------

构造函数提供了两种: 一种是无认证机制的, 一种是有认证机制的.
具体初始化过程放在initConnector函数中: 
  //连接到远程jmx的url
  JMXServiceURL url = new JMXServiceURL(serviceUrl);
  // 有认证
  JMXConnector connector = JMXConnectorFactory.connect(url, environment);
  // 无认证
  JMXConnector connector = JMXConnectorFactory.connect(url);          
  //获取和服务器的连接
  MBeanServerConnection connection = connector.getMBeanServerConnection();
  //这个是设置一个原则锁
  AtomicBoolean connected.set(true);

创建标准MBean代理:
public <T> T createMBeanProxy(final String mbeanName, final Class<T> mBeanInterface) {
  ObjectName objectName = buildObjectName(mbeanName);
  //返回一个标准MBean的代理 
  return (T) MBeanServerInvocationHandler.newProxyInstance(connection, objectName, mBeanInterface, false);
 }  
 
private ObjectName buildObjectName(final String mbeanName) {
  try {
   return new ObjectName(mbeanName);
  } catch (MalformedObjectNameException e) {
   throw new IllegalArgumentException("mbeanName:" + mbeanName + "不正确,无法转换为ObjectName.", e);
  }
 } 
 
按属性名直接读取MBean属性(无MBean的Class文件时使用):
ObjectName objectName = buildObjectName(mbeanName);
return connection.getAttribute(objectName, attributeName);                 

按属性名直接设置MBean属性(无MBean的Class文件时使用):
ObjectName objectName = buildObjectName(mbeanName);
Attribute attribute = new Attribute(attributeName, value);
connection.setAttribute(objectName, attribute);  

按方法名直接调用MBean方法(无MBean的Class文件时使用):
public Object invoke(final String mbeanName, final String methodName, final String[] paramClassNames,
   final Object[] paramValues) {
  try {
   ObjectName objectName = buildObjectName(mbeanName);
   return connection.invoke(objectName, methodName, paramValues, paramClassNames);
  } catch (JMException e) {
   throw new IllegalArgumentException("参数不正确", e);
  } catch (IOException e) {
   throw new IllegalStateException("连接出错", e);
  }
 }     

接下来, 我将使用我第一个JMX例子那篇文章中的JMX服务来演示一下这个JmxClientTemplate:
public static void main(String[] args) throws IOException {
  JmxClientTemplate template = new JmxClientTemplate(
    "service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector");
  // 得到mbean的属性
  System.out.println(template.getAttribute("bean:name=testJmxBean",
    "Name"));
  System.out.println(template
    .getAttribute("bean:name=testJmxBean", "Age"));
  System.out.println(template.getAttribute("bean:name=testJmxBean",
    "Values"));

  // 修改mbean的属性
  template.setAttribute("bean:name=testJmxBean", "Name", "I love you!");

  // 调用方法
  System.out.println(template.invoke("bean:name=testJmxBean",
    "getValues", new String[] {}, new Object[] {}));

  // 关闭
  template.close();
 }

几点注意:
1. mbean的名字一定要写全, 是bean:name=testJmxBean, 不是testJmxBean
2. 获取属性的值, 属性名首字母要大写
3. 获取方法的话, 方法名首字母不用大写 

posted on 2010-12-09 13:32  菊次郎  阅读(538)  评论(0)    收藏  举报