1. First, let's build the architecture, just build an ordinary javaweb project and it's OK. The specific directory is as follows:
For Xiaobai, you can take a closer look at the configuration of web.xml behind, and you can ignore the configuration of web.xml after a little research on javaweb.
2. Start the code and run the entire project. Let's talk about ideas.
(1).Controller annotation
package com.wuqi.annotation; import java.lang.annotation.*; /** * Created by wuqi on 2017/3/22. */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Controller { String value() default ""; }
(2).Quatifier annotation
package com.wuqi.annotation; import java.lang.annotation.*; /** * Created by wuqi on 2017/3/25. */ @Target({ ElementType.FIELD }) // Annotation representing the annotation @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Quatifier { String value() default ""; }
(3).RequestMapping annotation
package com.wuqi.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Shock on 2017/3/22. */ @Target({ ElementType.METHOD }) // Annotation on the method @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestMapping { String value() default ""; }
(4).Service annotation
package com.wuqi.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Shock on 2017/3/22. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Service { String value() default ""; }
--------------------------------------------------------------------------------------------------------------------------
(1).MyService interface
package com.wuqi.service.impl; import java.util.Map; /** * Created by wuqi on 2017/3/23. */ public interface MyService { int insert(Map map); int delete(Map map); int update(Map map); int select(Map map); }
(2).MyServiceImpl class
package com.wuqi.service.impl; import com.wuqi.annotation.Service; import java.util.Map; /** * Created by wuqi on 2017/3/23. */ @Service("MyServiceImpl") public class MyServiceImpl implements MyService { @Override public int insert(Map map) { System.out.println("MyServiceImpl:" + "insert"); return 0; } @Override public int delete(Map map) { System.out.println("MyServiceImpl:" + "delete"); return 0; } @Override public int update(Map map) { System.out.println("MyServiceImpl:" + "update"); return 0; } @Override public int select(Map map) { System.out.println("MyServiceImpl:" + "select"); return 0; } }
(3).SpringmvcService interface
package com.wuqi.service.impl; import java.util.Map; /** * Created by wuqi on 2017/3/23. */ public interface SpringmvcService { int insert(Map map); int delete(Map map); int update(Map map); int select(Map map); }
(4).MyServiceImpl class
package com.wuqi.service.impl; import com.wuqi.annotation.Service; import java.util.Map; /** * Created by wuqi on 2017/3/23. */ @Service("SpringmvcServiceImpl") public class SpringmvcServiceImpl implements SpringmvcService{ @Override public int insert(Map map) { System.out.println("SpringmvcServiceImpl:" + "insert"); return 0; } @Override public int delete(Map map) { System.out.println("SpringmvcServiceImpl:" + "delete"); return 0; } @Override public int update(Map map) { System.out.println("SpringmvcServiceImpl:" + "update"); return 0; } @Override public int select(Map map) { System.out.println("SpringmvcServiceImpl:" + "select"); return 0; } }
--------------------------------------------------------------------------------------------------------------------------
(1).SpringmvcController类
package com.wuqi.controller; import com.wuqi.annotation.*; import com.wuqi.service.impl.MyService; import com.wuqi.service.impl.SpringmvcService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Created by wuqi on 2017/3/23. */ @Controller("wuqi") public class SpringmvcController { @Quatifier("MyServiceImpl") MyService myService; @Quatifier("SpringmvcServiceImpl") SpringmvcService smService; @RequestMapping("insert") public String insert(HttpServletRequest request, HttpServletResponse response, String param) { myService.insert(null); smService.insert(null); return null; } @RequestMapping("delete") public String delete(HttpServletRequest request, HttpServletResponse response, String param) { myService.delete(null); smService.delete(null); return null; } @RequestMapping("update") public String update(HttpServletRequest request, HttpServletResponse response, String param) { myService.update(null); smService.update(null); return null; } @RequestMapping("select") public String select(HttpServletRequest request, HttpServletResponse response, String param) { myService.select(null); smService.select(null); return null; } }
--------------------------------------------------------------------------------------------------------------------------
(1). The DispatcherServlet class inherits the javax.servlet.http.HttpServlet class
package com.wuqi.servlet; import com.wuqi.annotation.*; import com.wuqi.controller.SpringmvcController; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Created by Shock on 2017/3/23. */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1L; List<String> packageNames = new ArrayList<String>(); // Instances of all classes, key is the value of the annotation, value is the instance of all classes Map<String, Object> instanceMap = new HashMap<String, Object>(); Map<String, Object> handerMap = new HashMap<String, Object>(); public DispatcherServlet() { super(); } public void init(ServletConfig config) throws ServletException { // Package scan, get the files in the package scanPackage("com.wuqi"); try { filterAndInstance(); } catch (Exception e) { e.printStackTrace (); } // create a mapping relationship handerMap(); // implement injection ioc(); } private void filterAndInstance() throws Exception { if (packageNames.size() <= 0) { return; } for (String className : packageNames) { Class<?> cName = Class.forName(className.replace(".class", "").trim()); if (cName.isAnnotationPresent(Controller.class)) { Object instance = cName.newInstance(); Controller controller = (Controller) cName.getAnnotation(Controller.class); String key = controller.value(); instanceMap.put(key, instance); } else if (cName.isAnnotationPresent(Service.class)) { Object instance = cName.newInstance(); Service service = (Service) cName.getAnnotation(Service.class); String key = service.value(); instanceMap.put(key, instance); } else { continue; } } } private void ioc() { if (instanceMap.isEmpty()) return; for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { // get all the properties inside Field fields[] = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true);// Accessible private properties if (field.isAnnotationPresent(Quatifier.class)); Quatifier quatifier = field.getAnnotation(Quatifier.class); String value = quatifier.value(); field.setAccessible(true); try { field.set(entry.getValue(), instanceMap.get(value)); } catch (IllegalArgumentException e) { e.printStackTrace (); } catch (IllegalAccessException e) { e.printStackTrace (); } } } SpringmvcController wuqi = (SpringmvcController) instanceMap.get("wuqi"); System.out.print(wuqi); } /** * Scan all files under the package * * @param Package */ private void scanPackage(String Package) { URL url = this.getClass().getClassLoader().getResource("/" + replaceTo(Package));// Escape all the . to get the corresponding path String pathFile = url.getFile(); File file = new File(pathFile); String fileList[] = file.list(); for (String path : fileList) { File eachFile = new File(pathFile + path); if (eachFile.isDirectory()) { scanPackage(Package + "." + eachFile.getName()); } else { packageNames.add(Package + "." + eachFile.getName()); } } } /** * Create a mapping relationship */ private void handerMap() { if (instanceMap.size() <= 0) return; for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) { Controller controller = (Controller) entry.getValue().getClass().getAnnotation(Controller.class); String ctvalue = controller.value(); Method[] methods = entry.getValue().getClass().getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping rm = (RequestMapping) method.getAnnotation(RequestMapping.class); String rmvalue = rm.value(); handerMap.put("/" + ctvalue + "/" + rmvalue, method); } else { continue; } } } else { continue; } } } private String replaceTo(String path) { return path.replaceAll("\\.", "/"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getRequestURI(); String context = req.getContextPath(); String path = url.replace(context, ""); Method method = (Method) handerMap.get(path); SpringmvcController controller = (SpringmvcController) instanceMap.get(path.split("/")[1]); try { method.invoke(controller, new Object[] { req, resp, null }); } catch (IllegalAccessException e) { e.printStackTrace (); } catch (IllegalArgumentException e) { e.printStackTrace (); } catch (InvocationTargetException e) { e.printStackTrace (); } } }
All the code has been posted, there is a web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <servlet-name>testServlet</servlet-name> <servlet-class>com.wuqi.servlet.DispatcherServlet</servlet-class> </servlet> <!-- ... --> <servlet-mapping> <servlet-name>testServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
3. Well, the code has been posted. Now we need to talk about the idea. Because there is code, we use the code to describe the idea, which makes it easier to understand the meaning of the code. Then you can try to write according to your own level.
- First we need to scan all the files in the package (DispatcherServlet -> init(ServletConfig config) -> scanPackage("com.wuqi")), that is, the files with annotations. Then all files under the package are stored in the packageNames collection.
- At this time, we got all the files under the package, but we only need the part of the file that contains the annotations we specified, so we need to filter out the files we want, and in the process of filtering, we can filter out the class Direct instantiation and storage through Class.forName. Store it in the instanceMap collection, and set the corresponding key value for it. The key value is the value of the class annotation.
- Then traverse all the objects in the instanceMap collection, get the object of the specified annotation, and obtain all the methods of the object through reflection, traverse all the methods, and store the method of the specified annotation into the handerMap, and the key is the spliced string ("/" + Object variable name + "/" + method name), value is the method (Method).
- Then we can traverse all objects in the instanceMap collection, obtain all property values (fields) collections of the object through reflection, and then traverse the property value collection, assign the property value with the specified annotation, and assign the property value through the set method of Field. object is injected. (that is, injecting the Service object into the Controller)
- Finally, a method of an object can be called through the invoke method of reflection. (At this time, the object is stored in instanceMap, and the method is stored in handlerMap)
Reference link: