簡単なservletフレームワーク
6506 ワード
本人はずっとservletフレームワークの原理を研究したいと思っていますが、研究するのは特に難しいです.どのwebフレームワークも非常に複雑だからです.何気なくネット上で簡単なものを見つけて、simplewebframeworkの作者が書いたようで、いいと思って、少し変えて、とても簡単なservletが形成されました.
さらにservletフレームワークの前に、現在の主流MVCフレームワークの多くはHttpServletを継承し、それを実現するservice方法であると考えたいと思います.直接実現するのはサービスメソッドなので、doGetやdoPostメソッドはどうでもいいです.
私たちが普段使っているdoGetメソッドやdoPostメソッドはサービスによって呼び出されるので、サービスこそHttpServiceの最も重要な方法であり、グローバルを制御するために使用されます.
それ以外に、私もいくつかのフレームワークが直接Filterインタフェースを実現して、これによってWEBフレームワークを実現することを見て、このようにしてもいいです.HttpServeretでできるすべての操作はFilterの実装で完了することができ、Filterはより強力であるからです.しかし、実現もさらに複雑です(sparkという簡単なものがあります).
次に研究したこの簡単なservletフレームワークについて説明します.主に2つのクラスから構成されています.1つは最も重要な制御転送クラスです.
器のメモリはかなり消費されますが、簡単なservletである以上、そんなに考える必要はありません.
次にcontrollerのurlをこのインスタンスに対応させ、1つのmapに保存し、このmapをservletContextに入れます.
このController注記は非常に簡単です.
servletPackageというパラメータは、コントローラに対応するパッケージを指定することを意味し、listenerがファイルをスキャンする効率が向上します.
このようなものはすべて装備されてから実際のコントローラを書くことができます.
さらにservletフレームワークの前に、現在の主流MVCフレームワークの多くはHttpServletを継承し、それを実現するservice方法であると考えたいと思います.直接実現するのはサービスメソッドなので、doGetやdoPostメソッドはどうでもいいです.
私たちが普段使っているdoGetメソッドやdoPostメソッドはサービスによって呼び出されるので、サービスこそHttpServiceの最も重要な方法であり、グローバルを制御するために使用されます.
それ以外に、私もいくつかのフレームワークが直接Filterインタフェースを実現して、これによってWEBフレームワークを実現することを見て、このようにしてもいいです.HttpServeretでできるすべての操作はFilterの実装で完了することができ、Filterはより強力であるからです.しかし、実現もさらに複雑です(sparkという簡単なものがあります).
次に研究したこの簡単なservletフレームワークについて説明します.主に2つのクラスから構成されています.1つは最も重要な制御転送クラスです.
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String uri = request.getRequestURI();
// .do
uri = uri.substring(request.getContextPath().length(), uri.length() - 3);
@SuppressWarnings("unchecked")
Map<String,Object> map = (Map<String,Object>) this.getServletContext().getAttribute("mapPath");
if (map.containsKey(uri)) {
// http uri Action
Object obj = map.get(uri);
// http
String methodName = request.getParameter("method");
// null, Action index
if (methodName == null) {
methodName = "index";
}
Method method = null;
try {
//
method = obj.getClass().getMethod(methodName,
HttpServletRequest.class, HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException(" " + obj.getClass().getName()
+ " " + methodName + " !!!");
}
try {
// Controller
method.invoke(obj, request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
このクラスの構想は、リクエストパスを介してコントローラに対応するインスタンスを見つけ、インスタンス内の具体的な方法を呼び出すことである.このインスタンスの生成はリスナーで行われ、リスナーでインスタンスを生成するメリットがあります.リスナーはウェブサーバを起動するときに自動的にロードされます.そうすると、最初からサーバを起動するときにすべてのコントローラをインスタンス化し、servletContextに存在します.もちろん、工事が大きすぎたり、コントローラが多すぎたりすると、このようなサービスは器のメモリはかなり消費されますが、簡単なservletである以上、そんなに考える必要はありません.
public class LoadServletListener implements ServletContextListener{
// Map key URI,value URI Action (Action )
private static Map<String, Object> map = new HashMap<String, Object>();
@Override
public void contextDestroyed(ServletContextEvent event) {
if(map!=null)
map=null;
}
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext context = event.getServletContext();
String servletPackage = context.getInitParameter("servletPackage");
String classPath = context.getRealPath(
"/WEB-INF/classes/"+servletPackage.replace('.',File.separatorChar));
scanClassPath(new File(classPath));
context.setAttribute("mapPath", map);
System.out.println(map);
}
/*
* , Control , value(URI) Map key,
* Map value
*/
private void scanClassPath(File file) {
try {
if (file.isFile()) {
if (file.getName().endsWith(".class")) {
String path = file.getPath();
MyClassLoader myClassLoader = new MyClassLoader(
this.getClass().getClassLoader());
Class<?> clazz = myClassLoader.load(path);
Controller controller = (Controller) clazz.getAnnotation(Controller.class);
if (controller != null) {
String uri = controller.value();
Object action = clazz.newInstance();
map.put(uri, action);
}
}
} else {
File[] files = file.listFiles();
for (File child : files) {
scanClassPath(child);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// ,
class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> load(String path) {
FileInputStream fis = null;
try {
fis = new FileInputStream(path);
byte[] buf = new byte[fis.available()];
int len = 0;
int total = 0;
int fileLength = buf.length;
while (total < fileLength) {
len = fis.read(buf, total, fileLength - total);
total = total + len;
}
return super.defineClass(null, buf, 0, fileLength);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
fis = null;
}
}
}
}
}
これがそのインスタンス化コントローラクラスのリスナーで、インスタンス化クラスというプロセスは少し複雑で、まずパスを通じて相応のclassファイルを見つけて、それからClassLoaderを通じてこのclassファイルの内容をロードして1つのClassクラスを生成して、更にこのClassクラスを通じて相応のインスタンスを生成します.次にcontrollerのurlをこのインスタンスに対応させ、1つのmapに保存し、このmapをservletContextに入れます.
このController注記は非常に簡単です.
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value();
}
実は个人はこのControllerが要らないことができると思って、もっと良いことを加えるしかなくて、以下は更に基本的なwebを譲ります.xml構成を貼り付けます. <context-param>
<param-name>servletPackage</param-name>
<param-value>com.controller</param-value>
</context-param>
<listener>
<listener-class>com.zit.LoadServletListener</listener-class>
</listener>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.zit.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
servletPackageというパラメータは、コントローラに対応するパッケージを指定することを意味し、listenerがファイルをスキャンする効率が向上します.
このようなものはすべて装備されてから実際のコントローラを書くことができます.
@Controller("/hello")
public class HelloController {
public void index(HttpServletRequest request, HttpServletResponse response)
throws Exception {
request.getRequestDispatcher("/pages/hello.jsp")
.forward(request, response);
}
}
のような簡単なservletフレームワークも形成され、少なくともservletを直接書くよりも少し簡単であり、後で他のservletフレームワークを研究するために良い参照を提供した.