注冊協議
URL的static URLStreamHandler getURLStreamHandler(String protocol) 方法用於獲取獲取協議處理類
URL提供了兩種注冊協議的途徑。
1)設置URLStreamHandlerFactory,2)設置jvm啟動參數Java.protocol.handler.pkgs。
兩者可以同時使用。
設置URLStreamHandlerFactory
URL的方法
public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
synchronized (streamHandlerLock) {
if (factory != null) {
throw new Error("factory already defined");
}
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkSetFactory();
}
handlers.clear();
factory = fac;
}
}
public interface URLStreamHandlerFactory {
URLStreamHandler createURLStreamHandler(String protocol);
}
整個jvm只能設置一次,再次設置不起作用。調用URL.setURLStreamHandlerFactory(fac)。
一般是在服務器的代碼中設置,比如tomcat,jboss ,was等,用於注冊服務器自己的協議,應用級沒法設置,因為服務器已經設置過了,應用即使設置了也不起作用。
啟動參數-DJava.protocol.handler.pkgs
通過-DJava.protocol.handler.pkgs=cn.ccb.wfcp注冊自定義協議的包。要求協議處理類的類名必須是Handler,包名的最後是協議名。示例如下,定義了brules協議。
package cn.ccb.wfcp.brules;
public class Handler extends URLStreamHandler {
如果要定義多個協議包就用"|"分割,比如-DJava.protocol.handler.pkgs=cn.ccb.wfcp|cn.ccb.wfcp22.
jvm內置的協議也是按照上面的方式定義的,但不用通過-DJava.protocol.handler.pkgs注冊,而是將內置的協議包拼接到後面。內置協議都在sun.Net.www.protocol包下面。
獲取到Handler類名後去加載class。Class cls = null;
try {
cls = Class.forName(clsName);
} catch (ClassNotFoundException e) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
cls = cl.loadClass(clsName);
}
}
if (cls != null) {
handler =
(URLStreamHandler)cls.newInstance();
}
但是只能加載到jvm classpath下的class,內置協議的class都可以加載到。如果自定義的協議類不加入jvm 的 classpath就不能被加載到,所以必須放入jvm 的classpath中,一般情況下自定義的協議是業務相關的,這樣就必須將業務相關的類也放入到jvm 的classpaht中,而業務類是在服務器中運行的,不應該放入更底層的jvm classpath中,要想辦法讓協議處理類與業務類解耦,這樣業務類就不需要放入jvm classpath中了。
解耦示例如下,Handler ,RulesURLConnection ,IRulesFiles 三個類在jvm classpath中
package cn.ccb.wfcp.brules;
。。。。。
public class Handler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return new RulesURLConnection(u);
}
}
package cn.ccb.wfcp.brules;
。。。。。
public class RulesURLConnection extends URLConnection {
@Override
public long getLastModifIEd() {
return getIRulesFiles().getLastModifIEd();
}
private IRulesFiles getIRulesFiles() {
IRulesFiles files = null;
try {
Class rulClass = null;
rulClass = Class.forName("cn.ccb.wfcp.brules.protocol.RulesFiles",
true, Thread.currentThread().getContextClassLoader());
//通過自定義classloader的方式控制實現類的加載
files = (IRulesFiles) rulClass.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return files;
}
@Override
public InputStream getInputStream() throws IOException {
return getIRulesFiles().getInputStream();
}
package cn.ccb.wfcp.brules;
。。。。。。。。
public interface IRulesFiles {
public List getRuleElements();
public long getLastModifIEd();
public InputStream getInputStream() throws IOException;
}
業務類,調用其他業務類
package cn.ccb.wfcp.brules.protocol;
。。。。
public class RulesFiles implements IRulesFiles{
@Override
public long getLastModifIEd() {
return RuleFilesDAOImpl.instance().getLastModifIEd();