解惑

解己之惑,解人之惑

分类:Java (第16页共20页)

Java技术

MockEJB测试框架之自动发布EJB

前段时间大致介绍了下这个测试框架,目前还没有完全完成,这里先慢慢介绍下框架得构成,这个是第一篇。

其实MockEJB提供的功能还是比较简单的,做单元测试需要我们自己写代码发布Bean,例如发布一个Session Bean:
            SessionBeanDescriptor sampleServiceDescriptor =
                new SessionBeanDescriptor( SampleService.JNDI_NAME,
                SampleServiceHome.class, SampleService.class, new SampleServiceBean() );
             mockContainer.deploy( sampleServiceDescriptor );

其实每个EJB工程都应该有现成的EJB配置文件(ejb-jar.xml、jboss.xml、jbosscmp-jdbc.xml),因此这个发布工作应该可以自动完成,思路就是自己读取那些配置文件获得EJB的配置信息。
然后就是要修改lookup的过程,由于我们的工程提供一个共通的接口来进行lookup,所以问题就演变为实现一个那个接口。对于其它的项目,应该是类似的,如果是直接使用Context的lookup,那么对于MockEJB而言就是扩展MockContext,覆盖lookup方法,先查找,找到目标就返回,没有的话尝试根据读取的EJB配置信息自动发布需要的EJB。这样,我们就在单元测试中可以直接获取EJB,而不用再进行发布了。

解析XML的时候完全忽略DTD

之所以要这么做是因为我们的XML肯定是合法的,不需要验证,另外我们的网络需要代理才能上网,解析的时候会很慢,不需要解析的时候运行只要不到一分钟,解析要两分钟以上,有时候甚至需要10分钟左右。
可能有人认为很简单,只需要设置DocumentBuilderFactory.setValidating(false),其实这个只能让解析器不验证DTD,解析器还是会读取DTD的,解决的方法是实现EntityResolver接口,对于我们的系统,我实现的类的代码为:
    public class IgnoreDTDEntityResolver implements EntityResolver
    {
        public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId) throws SAXException,
                java.io.IOException
        {
            if (systemId.equals("http://www.jboss.org/j2ee/dtd/jbosscmp-jdbc_3_2.dtd")
                    || systemId.equals("http://java.sun.com/dtd/ejb-jar_2_0.dtd")
                    || systemId.equals("http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd"))
                return new InputSource(new ByteArrayInputStream("<?xml version=’1.0′ encoding=’UTF-8′?>".getBytes()));
            else
                return null;
        }
    }

稍微说明下方法的两个参数publicId和systemId,假设DTD声明为:
<!DOCTYPE jbosscmp-jdbc PUBLIC "-//JBoss//DTD JBOSSCMP-JDBC 3.2//EN" "http://www.jboss.org/j2ee/dtd/jbosscmp-jdbc_3_2.dtd">
那么publicId为-//JBoss//DTD JBOSSCMP-JDBC 3.2//EN
systemId为http://www.jboss.org/j2ee/dtd/jbosscmp-jdbc_3_2.dtd
你可以根据自己的需要进行处理。

给Java程序设置代理

其实非常的简单,记在这里备忘。

        System.getProperties().put("proxySet", "true");
        System.getProperties().put("proxyHost", "10.10.10.10");
        System.getProperties().put("proxyPort", "808");

不要使用轮询

公司产品要集成LDAP,可以支持5个LDAP服务器,我们要写代码定期和LDAP服务器的信息进行同步,但是每个LDAP服务器的同步周期是变化的,用户可以配置。最简单的方式就是每个LDAP起一个线程做这个工作,但是架构师不允许太多的线程,所以要用一个主线程来控制。本来负责这个功能的人要使用轮询的方式,因为他觉得用户什么时候修改那个周期是不确定的,所以要一直查。其实很简单,如果其它的地方修改了那个周期,它通知那个主线程哪个服务器的周期修改了就行,然后主线程中断休眠并重新计算应该休眠的时间。主线程大部分时间都处于休眠状态,每次都会重新计算下一次应该休眠多长时间,这样程序的性能就大大的提高了。

演示代码如下:
阅读全文

J2SE仅仅是基础

也许这个名称本身已经老了,因为J2SE这个说法已经被JavaSE取代,但是很多人似乎一直停留在JDK1.4的时代,包括我在内。
就我而言,J2SE和Java几乎是同义词,而如果你要做Java开发,那么要么你做J2EE相关的开发,要么做J2ME相关的开发,纯粹的J2SE开发可能就是用Java做GUI程序了,但是估计这个比例是Java相关工作中最小的。
所以严格而言,你学会了Java语言并不意味着你可以开始Java的开发,这个仅仅是开始,要真正的可以工作,你需要学习其他很多东西。而且其实很多人“学会”了Java仅仅停留在语法的学习以及简单的API的使用。

但是。。。。。。
你还是可以找到Java的工作,如果你运气好的话,你可以做一些外包的工作,你根本无需掌握什么语言,按照例子写就可以了,很简单,很多做外包好几年的人出去找非外包的工作可能很难,特别是自己并没有努力去学习,仅仅停留在应付工作需要的情况下。

Java是很有意思的,它衍生出来的东西很多,你永远有继续学习的空间。

Response被关闭

这个是一个朋友问起的,他的后台有一些错误信息,大意就是response的流被关闭了。这个问题我原来遇到过一次,出错的原因是我的代码走到一个地方的时候我foward到另外的页面去了,但是代码并没有return,而是继续执行,并且后续的代码对response还继续写入内容了,报错的地方就发生在那个继续写入内容的地方。
但是这个朋友检查了他的代码,不是这个因素,他后来自己上网查了一下,发现是另外的原因,他的jsp代码是:
<jsp:include page="xxx.do?flag=true">
他使用的是struts,我也不清楚为什么会这样,但是猜测struts在进入新的action的时候会做一些工作,特别是对response的处理。有时间再仔细研究下原因。

JDBC中的日期问题

不知道其它的人有没有遇到,我以前是没有注意的,这次产品升级中提到这个问题。我们原来向数据库插入日期的时候,使用的是PreparedStatement,插入日期参数的时候一般是使用的setDate(int parameterIndex, Date x),不知道有没有注意到还有一个同名的方法:setDate(int parameterIndex, Date x, Calendar cal),多了一个Calendar参数,要说清楚这个问题,还需要从Date类说起,这个类的底层实现是用一个long值存储一个毫秒数,它是相对GMT时间的1970年1月1日的,所以从原意上讲,Date是没有时区的,但是我们在使用Date的时候经常使用的字符串的形式,这样Date在被格式化为字符串的时候才涉及到时区的概念。那个三个参数的格式的最后一个参数就是指定了存储到数据库的时候需要使用的时区,不指定的时候使用系统的当前时区。

生成各种IM图标

现在好像很流行这种IM图标的方式,可能是因为原来文字的方式容易招致垃圾邮件,而且也不太美观,现在好了,把你的信息写进去生成就行了,就是不知道这个生成的站会不会记下你的信息拿去卖?这年头,享受一点服务都担惊受怕的,生怕又被人给卖了。

另外再推荐一个生成favicon.ico的站点:http://www.html-kit.com/favicon/

以及一个这些东东的汇总页面: 汇总各类在线制作图标站点

Java面试中的经典对比问题

工作这些年,经历的面试也不少,提问的人似乎都喜欢问一些进行比较的问题,整理下我记忆中的,不给出答案,自己搜索下吧,等我有时间的时候再慢慢的整理。

  • HashTable和HashMap
  • Vector和ArrayList
  • Statement和PreparedStatement
  • InputStream和Reader以及OutputStream和Writer
  • truncate和delete(数据库)
  • function和procdure(数据库)
  • package和procdure(数据库)
  • Interface和Abstract class
  • Swing和AWT
  • Thread和Runnable
  • Exception和Error

在目录中查找类位于哪个jar包中

做Java开发的人可能都遇到过面对一大堆的jar包但是自己不知道需要的那些个类到底位于哪个jar包中,使用下面的代码,这个问题就可以迎刃而解了。
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class FindInJar {
    public String className;

    public ArrayList jarFiles = new ArrayList();

    public FindInJar() {
    }

    public FindInJar(String className) {
        this.className = className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public List findClass(String dir, boolean recurse) {
        searchDir(dir, recurse);
        return this.jarFiles;
    }

    protected void searchDir(String dir, boolean recurse) {
        try {
            File d = new File(dir);
            if (!d.isDirectory()) {
                return;
            }
            File[] files = d.listFiles();
            for (int i = 0; i < files.length; i++) {
                if (recurse && files[i].isDirectory()) {
                    searchDir(files[i].getAbsolutePath(), true);
                } else {
                    String filename = files[i].getAbsolutePath();
                    if (filename.endsWith(".jar")||filename.endsWith(".zip")) {
                        ZipFile zip = new ZipFile(filename);
                        Enumeration entries = zip.entries();
                        while (entries.hasMoreElements()) {
                            ZipEntry entry = (ZipEntry) entries.nextElement();
                            String thisClassName = getClassName(entry);
                            if (thisClassName.equals(this.className) || thisClassName.equals(this.className + ".class")) {
                                this.jarFiles.add(filename);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List getFilenames() {
        return this.jarFiles;
    }

    protected String getClassName(ZipEntry entry) {
        StringBuffer className = new StringBuffer(entry.getName().replace(‘/’, ‘.’));
        return className.toString();
    }

    public static void main(String args[]) {
        FindInJar findInJar = new FindInJar("javax.mail.Session");
        List jarFiles = findInJar.findClass("d:/libs/", true);
        if (jarFiles.size() == 0) {
            System.out.println("Not Found");
        } else {
            for (int i = 0; i < jarFiles.size(); i++) {
                System.out.println(jarFiles.get(i));
            }
        }
    }
}

main方法中的findClass方法的第二个参数是是否对指定的目录递归进行处理,一般都会要这样做的吧。

更早的文章 更新的文章

© 2025 解惑

本主题由Anders Noren提供向上 ↑