一直以来,整合Apache HTTP Server和其他Java容器时,可能你最好的选择就是mod_jk,但是mod_jk在Apache和外部Java服务器之间使用socket来进行协议转换,性能不能尽如人意。
正如我上一篇博客里说的,mod_java通过在apache嵌入的JVM中直接执行Java来响应HTTP请求,当然是要快于mod_jk的。
但是缺点是,不是Servlet API(虽然实现Servlet API不是很难,但是工作量肯定很大的),优点是,接口很清晰,很灵活,可以做到的事情也就很多。
那么如何开发一个基于mod_java的java handler呢?OK,假设你要在Apache里响应所有/test/*上的请求.
你要做的是:
1)配置Apache启用mod_java
LoadModule java_module modules/mod_java.so
<mod_java your_main_class>
JVMLibrary D:\jdk6\jre\bin\server\jvm.dll
CurDir D:\apache-tomcat-6.0.14
ADDJVMOpt -Djava.class.path=D:\apache-tomcat-6.0.14\bin\bootstrap.jar;D:\dev\vccode\mod_java\mod_java.jar
ADDJVMOpt -Djava.library.path=D:\apache-tomcat-6.0.14\bin
ADDJVMOpt -Dcatalina.home=D:\apache-tomcat-6.0.14
ADDJVMOpt -Duser.dir=D:\apache-tomcat-6.0.14
ADDJVMParam start
ADDJVMStopParam stop
ADDJavaHandler javatest com.yovn.apache.modj.HelloWorld
</mod_java>
这里main_class是可选的,如果有,那么JVM启动时自动调用main方法。
2)在配置文件里加入你将要开发的Java Handler
想上面文件中的
ADDJavaHandler javatest com.yovn.apache.modj.HelloWorld
这里 javatest是handler名字,后面是你的实现的class
3)在配置文件里告诉Apache 你的handler名字对应的路径
<Location /test>
    SetHandler javatest
</Location>
完成这些配置动作后,apache在收到到/test/*的请求后mod_java会call你的handler class的processRequest方法了。
RequestHandler接口如下定义,你的Handler都需要实现该接口:
package com.yovn.apache.modj;
import java.io.IOException;
/**
 * @author yovn
 * 
 */
public  interface RequestHandler {
    public abstract void processRequest(ModJRequest request) throws IOException,
            ModJavaException;
}
正如你看到的很简单的接口,但是ModJRequest就不简单了,该接口代表你跟Apache通行的直接的接口,目前定义如下:
package com.yovn.apache.modj;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
 * @author yovn
 *
 */
public interface ModJRequest {
    
    /**
     * 
     * @param name
     * @return the request header value of that name
     */
    String getRequestHeader(String name);
    
    /**
     * 
     * @return similar as HttpServletRequest.getRequestURI()
     */
    String getRequestURI();
    /**
     * 
     * @param name header name
     * @param value header value
     */
    void setResponseHeader(String name,String value);
    
    /**
     * 
     * @param type 'text/html' etc.. 
     */
    void setContentType(String type);
    
    /**
     * 
     * @param code response code
     */
    void setResponseCode(int code);
    
    /**
     * 
     * @return HTTP method
     */
    String getMethod();
    
    
    /**
     * Give you the  chance when you need push datas to client
     * Also,you can use it to close a connection 
     * Note:
     * HTTP Server may close the connection when it timeout automatically.
     * When you pass use an invalid connection id to call some function , it will failed.
     * @see com.yovn.apache.modj.ApacheModule#flushConnection(long, byte[], int, int)
     * @see com.yovn.apache.modj.ApacheModule#closeConnection(long)
     * @return the connection id for this request.
     */
    long getConnectionId();
    
    /**
     * same as HttpServletRequest.getServletInputStream
     * @return 
     */
    InputStream getRequestInputStream();
    
    /**
     * same as HttpServletResponse.getServletOutputStream
     * @return
     */
    OutputStream getResponseOutputStream();
    
    
    /**
     * You should not call the {@link #getRequestInputStream()} before you call this method this method.
     * In other words, You should either use this method or {@link #getRequestInputStream()}  to do read data from clients
     * @return the direct byte buffer from native side
     * @throws IOException
     */
    ByteBuffer readTotalRequestBody()throws IOException;
    
    
    /**
     * Use apache's apr_send_fd to send a file.
     * Before send file, you may need setup proper HTTP headers, such as 'Content-Disposition' 
     * @param fileName
     * @return 
     * @throws IOException
     */
    boolean sendFile(String fileName)throws IOException;
}
如你所看,基本可以做任何事情(如果还有你想要而没有请一定要告诉我哦)!
下面给个发送文件的例子:
/**
 * 
 */
package com.yovn.apache.modj;
import java.io.File;
import java.io.IOException;
/**
 * @author yovn
 *
 */
public class HelloWorld implements RequestHandler {
    /**
     * 
     */
    public HelloWorld() {
        // TODO Auto-generated constructor stub
    }
    /*
     * (non-Javadoc)
     * 
     * @see com.yovn.apache.modj.RequestHandler#processRequest(ModJRequest request)
     */
    public void processRequest(ModJRequest request) throws IOException,
            ModJavaException {
        request.setContentType("APPLICATION/OCTET-STREAM");
    
        File f=new File("D:\\cspace\\mod_java\\release\\ddd.bin");
        request.setResponseHeader("Content-Disposition", "attachment;filename=\"ddd.bin\"");
        request.setResponseHeader("Content-Length",f.length()+"");
        
        request.sendFile(f.getCanonicalPath());
        
    }
}
下载:
mod_java_0.1