Spring手寫簡化版MVC流程詳解
spring是一個非常流行的技術框架,其中spring mvc組件在其中非常重要的地位,主要面要客戶端提供服務,我們今天來手寫一個簡化版的mvc,且包括ioc部分,主要利用servlet機制來實現(xiàn),類的關系如下:
準備注解類,類于spring的@Autowired、@Service、@Controller、@RequestMapping、@RequestParam
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CSAutowired { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CSController { String value() default ""; } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CSRequestMapping { String value() default ""; } @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CSRequestParam { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CSService { String value() default ""; }
準備service interface
public interface IDemoService { public String get(String name); }
準備service實現(xiàn)類,利用@CSService
@CSService public class DemoService implements IDemoService { @Override public String get(String name) { return "My name is "+name; } }
準備對外服務的類,主要利用@CSController注解
@CSController @CSRequestMapping("/demo") public class DemoAction { @CSAutowired private IDemoService demoService; @CSRequestMapping("/query") public void query(HttpServletRequest req, HttpServletResponse resp, @CSRequestParam("name") String name){ String result=demoService.get(name); try { resp.getWriter().write(result); } catch (IOException exception) { exception.printStackTrace(); } } @CSRequestMapping("/add") public void add(HttpServletRequest req, HttpServletResponse resp, @CSRequestParam("aa") Integer a,@CSRequestParam("b") Integer b){ try { resp.getWriter().write(a+"+"+b+"="+(a+b)); } catch (IOException exception) { exception.printStackTrace(); } } @CSRequestMapping("/remove") public void remove(HttpServletRequest req, HttpServletResponse resp, @CSRequestParam("id") Integer id){ try { resp.getWriter().write("id="+id); } catch (IOException exception) { exception.printStackTrace(); } } }
準備servlet
主要實現(xiàn)了以下功能:
1).根據(jù)@CSController對外服務的url如何mapping到具體方法 doHandlerMap
2).service和controller bean的管理 iocBeans
3).如何實列化bean doInstance
4).如何獲取url中參數(shù)值 doDispatch中
5).找到需要加載的class doScanner
6).如何自動autowired doAutoWried
public class CSDispatchServlet extends HttpServlet { public static String urlPattern="/custom"; private void doDispatch(HttpServletRequest request,HttpServletResponse response) throws Exception{ String url=request.getRequestURI(); String contextPath=request.getContextPath(); url=url.replace(urlPattern,""); if(!handlerMap.containsKey(url)){ response.getWriter().write("404 not found!"); return; } Method method=handlerMap.get(url); Annotation[][] methodParameterAnnotations= method.getParameterAnnotations(); Parameter[] methodParameters= method.getParameters(); Annotation[][] paramerterAnnotations=method.getParameterAnnotations(); ArrayList<Object> methodParameterValues=new ArrayList<Object>(); Map<String,String[]> requestParams= request.getParameterMap(); int parmeterCnt=0; for(Parameter parameter:methodParameters){ if(parameter.getType()==HttpServletRequest.class ){ methodParameterValues.add(request); }else if(parameter.getType()==HttpServletResponse.class){ methodParameterValues.add(response); }else { String methodParamName=""; if(paramerterAnnotations[parmeterCnt].length>0) { Annotation annotation= paramerterAnnotations[parmeterCnt][0]; if(annotation instanceof CSRequestParam) { methodParamName = ((CSRequestParam) annotation).value(); } } if("".equals(methodParamName.trim())){ methodParamName=parameter.getName(); } String value=""; //String value=Arrays.toString(requestParams.get(methodParamName)); if(requestParams.get(methodParamName).length>1) value=Arrays.toString(requestParams.get(methodParamName)); else if(requestParams.get(methodParamName).length==1) value= requestParams.get(methodParamName)[0]; else value="999999"; if(parameter.getType()==String.class) methodParameterValues.add(value); else if(parameter.getType()==Integer.class) { try { methodParameterValues.add(Integer.parseInt(value)); } catch (Exception e){ methodParameterValues.add(99999999); } }else { //可以擴展復雜類型轉換 } } parmeterCnt++; } String beanName=this.genBeanName(method.getDeclaringClass().getSimpleName()); method.invoke(this.iocBeans.get(beanName), methodParameterValues.toArray()); } private String genBeanName(String beanName){ if(beanName.length()>1) beanName=beanName.substring(0,0).toLowerCase()+beanName.substring(1); else beanName=beanName.toLowerCase(); return beanName; } @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 { try { this.doDispatch(req,resp); } catch (Exception exception) { exception.printStackTrace(); } } private ArrayList<String> classs=new ArrayList<String>(); private ConcurrentHashMap<String,Object> iocBeans=new ConcurrentHashMap<String,Object>(); private ConcurrentHashMap<String,Method> handlerMap=new ConcurrentHashMap<String,Method>(); private void doInstance() { try { for (String className : classs) { if (!className.contains(".")) continue; Class<?> clazz = Class.forName(className); String beanName=""; if (clazz.isAnnotationPresent(CSController.class)) { CSController controller = clazz.getAnnotation(CSController.class); beanName=controller.value(); }else if(clazz.isAnnotationPresent(CSService.class)){ CSService service=clazz.getAnnotation(CSService.class); beanName=service.value(); }else { continue; } Object instance=clazz.newInstance(); if("".equals(beanName.trim())) beanName=clazz.getSimpleName(); beanName=genBeanName(beanName); iocBeans.put(beanName,instance); if(clazz.isAnnotationPresent(CSService.class)){ for(Class c: clazz.getInterfaces()){ if(iocBeans.containsKey(c.getName())) continue; iocBeans.put(c.getName(),instance); } } } }catch (Exception e){ e.printStackTrace(); } } private void doAutoWried(){ for(Object o:iocBeans.values()){ if(o==null) continue; Class clazz=o.getClass(); if(clazz.isAnnotationPresent(CSService.class) || clazz.isAnnotationPresent(CSController.class)){ Field[] fields=clazz.getDeclaredFields(); for(Field f:fields){ if(!f.isAnnotationPresent(CSAutowired.class)) continue; CSAutowired autowired=f.getAnnotation(CSAutowired.class); String beanName=autowired.value(); if("".equals(beanName)) beanName=f.getType().getName(); f.setAccessible(true); try{ Object o1=iocBeans.get(beanName); f.set(o,iocBeans.get(beanName)); }catch (IllegalAccessException e){ e.printStackTrace(); } } } } } private void doHandlerMap(ServletConfig config){ for(Object o:iocBeans.values()){ if(!o.getClass().isAnnotationPresent(CSController.class)) continue; String baseUrl=""; if(o.getClass().isAnnotationPresent(CSRequestMapping.class)){ CSRequestMapping requestMapping=o.getClass().getAnnotation(CSRequestMapping.class); baseUrl=requestMapping.value(); } for(Method method: o.getClass().getMethods()){ if(method.isAnnotationPresent(CSRequestMapping.class)) { CSRequestMapping requestMapping=method.getAnnotation(CSRequestMapping.class); String url=baseUrl+requestMapping.value().replaceAll("/+","/"); String contextPath=config.getServletContext().getContextPath(); this.handlerMap.put(url,method); } } } } @Override public void init(ServletConfig config) throws ServletException { InputStream is=null; try{ System.out.println("custom servlet init........"); /* Properties configContext=new Properties(); is=this.getClass().getClassLoader().getResourceAsStream(config.getInitParameter("contextConfigLocation")); configContext.load(is); String scanPackage=configContext.getProperty("scanPackage"); */ Enumeration<String> enumerations= config.getInitParameterNames(); while (enumerations.hasMoreElements()){ System.out.println(enumerations.nextElement()); } doScanner("com.mesui.spring.custom"); doInstance(); doAutoWried(); doHandlerMap( config); }catch (Exception exception){ exception.printStackTrace(); }finally { } } private void doScanner(String scanPackage){ URL url= this.getClass().getClassLoader().getResource("") ; String filePath=""; try { filePath= URLDecoder.decode( url.getPath(),"UTF-8")+"/"+scanPackage.replaceAll("\\.","/"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } File classDir=new File(filePath); for(File file:classDir.listFiles()){ if(file.isDirectory()){ doScanner(scanPackage+"."+file.getName()); }else if(!file.getName().endsWith(".class")) { continue; } if(!file.isDirectory()) { String clzzName = (scanPackage + "." + file.getName().replace(".class", "")); //map.put(clzzName,null); classs.add(clzzName); } } } }
在利用spring的configuration類初始化servlet
這邊為了方便進行偷懶,這樣/custom/下的服務按照自已邏輯對對外服務,不按照spring mvc的進行,另外自已可以tomcat的web.xml中標記servlet完全脫離spring
@Configuration public class MybatisPlusConfig { @Bean public ServletRegistrationBean CustomServlet(){ return new ServletRegistrationBean(new CSDispatchServlet(),CSDispatchServlet.urlPattern+"/*"); } }
測試
結論
從上面的例子中我們可以看到自已寫一個mvc也很方便,不是什么難事,但是這個只是用于學習,畢竟spring是一個體系,我們自已不可能將所有內容重新寫一遍,但是自已寫著玩有助于對spring mvc和IOC的理解。
到此這篇關于Spring手寫簡化版mvc流程詳解的文章就介紹到這了,更多相關Spring mvc內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java基于jdbc連接mysql數(shù)據(jù)庫功能實例詳解
這篇文章主要介紹了java基于jdbc連接mysql數(shù)據(jù)庫功能,結合實例形式詳細分析了jdbc連接mysql數(shù)據(jù)庫的原理、步驟、實現(xiàn)方法及相關操作技巧,需要的朋友可以參考下2017-10-10SpringBoot服務端數(shù)據(jù)校驗過程詳解
這篇文章主要介紹了SpringBoot服務端數(shù)據(jù)校驗過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-02-02解決@PathVariable參數(shù)接收不完整的問題
這篇文章主要介紹了解決@PathVariable參數(shù)接收不完整的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java使用雙異步實現(xiàn)將Excel的數(shù)據(jù)導入數(shù)據(jù)庫
在開發(fā)中,我們經(jīng)常會遇到這樣的需求,將Excel的數(shù)據(jù)導入數(shù)據(jù)庫中,這篇文章主要來和大家講講Java如何使用雙異步實現(xiàn)將Excel的數(shù)據(jù)導入數(shù)據(jù)庫,感興趣的可以了解下2024-01-01