接下来分析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. 获取方法的话, 方法名首字母不用大写
浙公网安备 33010602011771号