偶然看到一篇100多行實現SpringMvc的博客,閱讀後整理加實現出來。大家共勉!(紙上得來終覺淺,絕知此事要躬行。) 實現Spring的部分。 代碼解析如下: 1、首先創建Servelt,繼承HttpServlet。覆蓋init/doGet/doPost方法。 2、配置web.xml 2.1、配 ...
偶然看到一篇100多行實現SpringMvc的博客,閱讀後整理加實現出來。大家共勉!(紙上得來終覺淺,絕知此事要躬行。)
實現Spring的部分。
- Bean工廠,統一創建Bean;
- IOC,實現Bean的依賴註入;
- DispatchServlet,SpringMVC的路徑映射。
代碼解析如下:
1、首先創建Servelt,繼承HttpServlet。覆蓋init/doGet/doPost方法。
@Override public void init() throws ServletException { try { // 初始化配置文件 initConfig(super.getServletConfig().getInitParameter(CONFIG_NAME)); // 掃描類 doScanPackage(configProperties.getProperty("packageScan")); // 載入類 initBeanInitializing(); // 依賴註入 initBeanAutowired(); // 路徑映射 initServletDispatch(); } catch (Exception e) { e.printStackTrace(); } System.out.println("====>beanFactory:\n"+beanFactory); System.out.println("====>requestMap:\n"+requestMap); } @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{ doDispatch(req,resp); }
2、配置web.xml
<servlet> <servlet-name>cwDispatchServlet</servlet-name> <servlet-class>com.cw.servlets.CWDispatchServlet</servlet-class> <init-param> <param-name>dispatchConfig</param-name> <param-value>config.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cwDispatchServlet</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
2.1、配置文件config.properties在根目錄,如下
# 設置配置文件 packageScan=com.cw.demo
3、定義支持的註入,如
Autowired
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Inherited public @interface CWAutowired { String value() default ""; }
Controller
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface CWController { String value() default ""; }
RequestMapping
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) @Inherited public @interface CWRequestMapping { String value() default ""; }
Service
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface CWService { String value() default ""; }
4、在Servlet的init方法中,依次實現
4.1、載入配置文件
private void initConfig(String configName){ InputStream inputStream = null; try { System.out.println("------->configName:"+configName); inputStream = this.getClass().getClassLoader().getResourceAsStream(configName); configProperties.load(inputStream); } catch (Exception e) { e.printStackTrace(); }finally { if(null != inputStream) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
4.1、掃描所有Java類
/** * 掃描類 * @Title: doScanPackage * @param packagePath * @return void */ private void doScanPackage(String packagePath) { System.out.println("path:"+packagePath.replaceAll("\\.", "/")); URL url = this.getClass().getClassLoader().getResource("/"+packagePath.replaceAll("\\.", "/")); File file = new File(url.getFile()); for(File sub:file.listFiles()) { if(sub.isDirectory()) { doScanPackage(packagePath+"."+sub.getName()); }else { String clsName = packagePath+"."+sub.getName().replace(".class",""); this.clsList.add(clsName); } } }
4.3、初始化類
private void initBeanInitializing() throws ClassNotFoundException, InstantiationException, IllegalAccessException { for(String clsName:clsList) { Class cls = Class.forName(clsName); if(cls.isAnnotationPresent(CWController.class)) { String name = cls.getSimpleName(); beanFactory.put(lowerFirstChar(name) , cls.newInstance()); }else if(cls.isAnnotationPresent(CWService.class)) { CWService service = (CWService) cls.getAnnotation(CWService.class); String defaultName = service.value(); if(!"".equals(defaultName)) { beanFactory.put(defaultName, cls.newInstance()); }else { Class[] interfaces = cls.getInterfaces(); Object instance = cls.newInstance(); for(Class inter:interfaces) { beanFactory.put(lowerFirstChar(inter.getSimpleName()), instance); } } }else if(cls.isAnnotationPresent(CWComponent.class)){ String name = cls.getName(); beanFactory.put(lowerFirstChar(name), cls.newInstance()); } } }
4.4、完成類的依賴註入
private void initBeanAutowired() throws IllegalArgumentException, IllegalAccessException { for(Map.Entry<String, Object> entry:beanFactory.entrySet()) { Object bean = entry.getValue(); Field[] fields = bean.getClass().getDeclaredFields(); if(null == fields || fields.length ==0 ) { continue; } for(Field field:fields) { if(field.isAnnotationPresent(CWAutowired.class)) { String fieldTypeName = field.getType().getSimpleName(); field.setAccessible(true); field.set(bean, beanFactory.get(this.lowerFirstChar(fieldTypeName))); } } } }
4.5、完成request的路徑映射
private void initServletDispatch() { for(Map.Entry<String, Object> entry:beanFactory.entrySet()) { Object bean = entry.getValue(); System.out.println(entry.getKey()+":"+entry.getValue()); if(!bean.getClass().isAnnotationPresent(CWController.class)) { continue; } // 基本路徑 String basePath = ""; if(bean.getClass().isAnnotationPresent(CWRequestMapping.class)) { basePath = ((CWRequestMapping)bean.getClass().getAnnotation(CWRequestMapping.class)).value(); } System.out.println("=========>basePath:"+basePath); // 方法路徑 Method[] methods = bean.getClass().getMethods(); for(Method method:methods) { if(method.isAnnotationPresent(CWRequestMapping.class)) { String path = ((CWRequestMapping)method.getAnnotation(CWRequestMapping.class)).value(); requestMap.put(("/"+basePath +"/"+path).replaceAll("/+", "/"), method); } } } }
5、處理頁面請求
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException, IOException { String url = req.getRequestURI(); String contextPath = req.getContextPath(); url = url.replace(contextPath, "").replaceAll("/+", "/"); System.out.println("=========>request url:"+url); Method method = this.requestMap.get(url); if(null == method) { resp.getOutputStream().write("404 not found!".getBytes("UTF-8")); return; } String beanName = this.lowerFirstChar(method.getDeclaringClass().getSimpleName()); try { method.invoke(beanFactory.get(beanName), req,resp); }catch (Exception e) { e.printStackTrace(); resp.getOutputStream().write("404 not found!".getBytes("UTF-8")); } }
6、添加測試類了
HelloWorldAction.java
@CWController @CWRequestMapping("/h") public class HelloWorldAction { @CWAutowired private IUserService userService; @CWRequestMapping("/hello.htm") public void hello(HttpServletRequest request,HttpServletResponse response) { try { System.out.println(userService.getUserNameById(1L)); response.getWriter().write("hello World!"); response.flushBuffer(); } catch (IOException e) { e.printStackTrace(); } } }
IUserService.java
public interface IUserService { public String getUserNameById(Long id); }
UserServiceImpl.java
@CWService public class UserServiceImpl implements IUserService { @Override public String getUserNameById(Long id) { return "master"; } }
7、tomcat啟動,大功告成
http:127.0.0.1:8080/h/hello.htm
總結:
1、看別人的代碼,很簡單,自己實現就發現很多坑。關鍵還是要自己實踐。實踐!實踐!實踐!
備註:
1、參考來源
https://www.toutiao.com/i6636629045259796995/
2、工程源碼
https://pan.baidu.com/s/1F0el_nwDJ99-AYueeH0esw