Since jdk1.3, Java has introduced the concept of dynamic proxy. Dynamic proxy helps you reduce the number of lines of code and improve code reusability. For example, you do not have to write the same log code lines for all the methods of the class, instead of the dynamic proxy class of the category class. Of course, this kind of convenience is conditional. This article briefly introduces the principle of Java Dynamic proxy, and implements the process of creating and calling a proxy servlet. 1. proxy pattern was popular before jdk1.3. Therefore, the proxy pattern generates a proxy class with the same interface as the class. You can encapsulate an implementation class by using the proxy class. 1. The purpose is to enhance the function of implementing a method of the class without changing the original source code.
2. Dynamic proxy with the popularity of proxy, Sun incorporated it into jdk1.3 to implement the dynamic proxy of Java. The difference between dynamic proxy and normal proxy mode is that the proxy class in dynamic proxy is dynamically generated by the java. Lang. Reflect. proxy class according to the interface definition at runtime using the Java reflection function. Combined with Java. Lang. Reflect. invocationhandler, You can enhance the implementation of existing classes. 2. The Custom Handler in the figure implements the invocationhandler interface. When the Custom Handler is instantiated, the implementation class is passed into the Custom Handler object. Custom Handler needs to implement the invoke method. This method can use Java reflection to call the implementation method of the class, and of course can implement other functions, such as adding log before and after calling the implementation class method. The proxy class dynamically generates an object of the interface implementation class according to the handler and the interface needing proxy. When you call this dynamically generated implementation class, you actually call the Custom Handler invoke method.
3. although there are many Web Application Server products, the servlet processing principle is similar: dynamically load the servlet and call the servlet init method (only called once ), and save it to the servlet container. When using Servlet, call the servlet service method. In this article, the dynamic proxy servlet interface is used to obtain information before and after method calls in the console when init and service are called. First, implement two servlets: DefaultServlet and userservlet package Org. colimas. servlet; import javax. servlet. servlet; import javax. servlet. servletexception; import javax. servlet. HTTP. httpservlet; public class DefaultServlet extends httpservlet implements servlet {public void Init () throws servletexception {super. init (); system. out. println (defaservlet servlet. class. getname () + ": Running init");} Public String getservletinf O () {return defaservlet servlet. class. getname () ;}} package Org. colimas. servlet; import Java. io. ioexception; import javax. servlet. servlet; import javax. servlet. servletexception; import javax. servlet. HTTP. httpservlet; import javax. servlet. HTTP. httpservletrequest; import javax. servlet. HTTP. httpservletresponse; public class userservlet extends httpservlet implements servlet {Private Static final long serial Versionuid =-701655479516504242l; Public void Init () throws servletexception {super. init (); system. out. println (userservlet. class. getname () + ": Running init");} protected void doget (httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception {system. out. println (userservlet. class. getname () + ": Do userservlet get");} Public String getservletinfo () {return userservlet. CIA SS. getname () ;}} then implements invocationhandlerpackage Org. colimas. webapp; import Java. lang. reflect. invocationhandler; import Java. lang. reflect. method; import javax. servlet. servlet; public class servlethandler implements invocationhandler {private servlet OBJ; Public servlethandler (servlet OBJ) {This. OBJ = OBJ;} public object invoke (Object arg0, method arg1, object [] arg2) throws throwable {If (arg1.getnam E (). compareto ("init") = 0) // {system. out. println (obj. getservletinfo () + ": init servlet starting... "); // added console output. Arg1.invoke (OBJ, arg2); // call the init method system. out. println (obj. getservletinfo () + ": init servlet ending... "); // added console output.} Else if (arg1.getname (). compareto ("service") = 0) {// system when the service is called. out. println (obj. getservletinfo () + ": Service starting... "); // added console output. Arg1.invoke (OBJ, arg2); // call the service method. System. Out. println (obj. getservletinfo () + ": service ending..."); // adds console output.} Return NULL;} implement servlet call package Org. colimas. webapp; import Java. lang. reflect. invocationhandler; import Java. lang. reflect. proxy; import javax. servlet. servlet; import javax. servlet. servletconfig; import javax. servlet. servletcontext; import javax. servlet. servletexception; public class servletwrapperimp {private class servletclass; private servletconfig config; private string _ servletname; private Servlet _ theservlet; private servletcontext context; Public servletwrapperimp (servletconfig config) {This. config = config; this. _ servletname = This. config. getservletname (); this. context = This. config. getservletcontext ();} public servlet getservlet () throws servletexception {destroy (); try {webappclassloader loader = new webappclassloader (this. getclass (). getclassloader (); // custom Class Loader string name = Getservletname (); // obtain the servlet name synchronized (context) {servlet theservlet = context from servletconfig. getservlet (name); // search for servlet if (theservlet = NULL) in servletcontext {// If servletcontext does not exist. Servletclass = loader. loadclass (name); // The servlet class is loaded by the class loader. Theservlet = (servlet) servletclass. newinstance (); // servlet instantiation. Webappcontext. addservlet (name, theservlet); // Save the servlet instance to servletcontext. Invocationhandler handler = new servlethandler (theservlet); // custom servlethandler, see servlethandler class. _ Theservlet = (servlet) proxy. newproxyinstance (theservlet. getclass (). getclassloader (), new class [] {servlet. Class}, Handler); // proxy class instantiation. _ Theservlet. INIT (config); // The servlet proxy object calls the init method. See the invoke method of servlethandler.} Else {// servletcontext already exists. Invocationhandler handler = new servlethandler (theservlet); // custom servlethandler, see servlethandler class. _ Theservlet = (servlet) proxy. newproxyinstance (theservlet. getclass (). getclassloader (), new class [] {servlet. class}, Handler); // proxy servlet interface, which dynamically generates and instantiates the proxy class.} Return _ theservlet; // return servlet proxy object} catch (classnotfoundexception ex1) {} catch (instantiationexception ex) {} catch (illegalaccessexception ex2) {} return NULL ;} public void destroy () {If (_ theservlet! = NULL) {_ theservlet. Destroy () ;}} protected string getservletname () {return _ servletname ;}} among them, servletconfig saves servlet-related information. Servletcontext stores all servlet objects. Webappclassloader is a custom Class Loader. For details, see http://blog.csdn.net/tyrone1979/archive/2006/09/03/1164262.aspx. Finally, write the test class main, which simulates 10 users accessing servlet, 5 Users accessing defaservlet servlet, and 5 Users accessing userservlet. Package Org. colimas. main; import Java. io. ioexception; import javax. servlet. servlet; import javax. servlet. servletconfig; import javax. servlet. servletexception; import Org. colimas. webapp. httpservletrequestwrapper; import Org. colimas. webapp. httpservletresponsewrapper; import Org. colimas. webapp. servletconfigimpl; import Org. colimas. webapp. servletwrapper; import Org. colimas. webapp. servletwrapperimp; import org. Colimas. webapp. webappcontext; public class main {private threadgroup _ threadgroup; private thread [] _ threads; string defaservservletname = "org. colimas. servlet. defaultServlet "; string userservletname =" org. colimas. servlet. userservlet "; webappcontext context = webappcontext. newinstance (); Public void dostart () {_ threadgroup = new threadgroup ("servlets"); int I = 0; _ threads = new servletthread [10]; // simulate 10 Users. For (I = 0; I <5; I ++) {_ threads [I] = new servletthread (_ threadgroup, new INTEGER (I ). tostring (), defaultservletname); _ threads [I]. start () ;}for (I = 5; I <10; I ++) {_ threads [I] = new servletthread (_ threadgroup, new INTEGER (I ). tostring (), userservletname); _ threads [I]. start () ;}/ *** @ Param ARGs */public static void main (string [] ARGs) {main _ main = new main (); _ main. dostart ();} // simulate the user thread private class servletth Read extends thread {private string servletname; Public servletthread (threadgroup group, string threadname, string servletname) {super (group, threadname); servletname = servletname;} // call the servlet service. public void run () {// servlet servletconfig Config = new servletconfigimpl (servletname, context); // call the Servlet Information. Servletwrapperimp wrapper = new servletwrapperimp (config); try {servlet defaservlet servlet = wrapper. getservlet (); // get the servlet object, which is actually the defaservlet servlet proxy object of the servlet. service (new httpservletrequestwrapper (), new httpservletresponsewrapper (); call the service method of the proxy object. See the invoke method of servlethandler.} Catch (servletexception e) {e. printstacktrace ();} catch (ioexception e) {}}} httpservletrequestwrapper and httpservletresponsewrapper implement httpservletrequest and httpservletresponse. The test result is as follows: Org. colimas. servlet. defaultServlet: init servlet starting...org. colimas. servlet. defaultServlet: Running initorg. colimas. servlet. defaultServlet: init servlet ending...org. colimas. servlet. userservlet: init servlet starting...org. colimas. servlet. userservlet: Running initorg. colimas. servlet. userservlet: init servlet ending...org. colimas. servlet. defaultServlet: Service starting...org. colimas. servlet. DEFA Ultservlet: Service ending...org. colimas. servlet. defaultServlet: Service starting...org. colimas. servlet. defaultServlet: Service ending...org. colimas. servlet. userservlet: Service starting...org. colimas. servlet. userservlet: Do userservlet getorg. colimas. servlet. userservlet: Service ending...org. colimas. servlet. userservlet: Service starting...org. colimas. servlet. userservlet: Do userservlet getorg. colimas. ser Vlet. userservlet: Service ending...org. colimas. servlet. userservlet: Service starting...org. colimas. servlet. userservlet: Do userservlet getorg. colimas. servlet. userservlet: Service ending...org. colimas. servlet. userservlet: Service starting...org. colimas. servlet. defaultServlet: Service starting...org. colimas. servlet. userservlet: Service starting...org. colimas. servlet. defaultServlet: Service starting...org. CO Limas. servlet. defaultServlet: Service starting...org. colimas. servlet. userservlet: Do userservlet getorg. colimas. servlet. defaultServlet: Service ending...org. colimas. servlet. userservlet: Do userservlet getorg. colimas. servlet. defaultServlet: Service ending...org. colimas. servlet. defaultServlet: Service ending...org. colimas. servlet. userservlet: Service ending...org. colimas. servlet. userservlet: service ending. .. The two servlets are initialized during the first load, called init, and then saved to servletcontext. The second operation is obtained directly from servletcontext and the service is executed. The red letter indicates the added output result in the proxy class. 4. Dynamic proxy restrictions JDK dynamic proxy cannot proxy all classes as you like. The second parameter of the proxy. newproxyinstance method can only be an interface array, that is, the proxy can only be a proxy interface.