日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

手写实现Spring(IOC、DI),SpringMVC基础功能

發(fā)布時間:2024/4/11 javascript 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手写实现Spring(IOC、DI),SpringMVC基础功能 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

手寫實現(xiàn)Spring(IOC、DI),SpringMVC功能

spring和springMVC的用法相信大家都不陌生,我簡單講下我實現(xiàn)的思路

spring階段事項
配置配置web.xml: init-param和Servlet
初始化啟動讀取web.xml,加載spring配置文件init()
獲取配置文件里的掃包路徑,掃描得到相關(guān)的class集合
實例化相關(guān)的實體類,注入到ioc容器中
依賴注入(byType or byName)
獲取handlerMaping url和method的映射關(guān)系
執(zhí)行轉(zhuǎn)發(fā)獲取url請求地址
根據(jù)url匹配對應(yīng)的controller的method
通過反射調(diào)用對應(yīng)的method,獲取controller的返回結(jié)果,解析

代碼

package com.chenpp.spring.web.servlet;public class CPDispatcherServlet extends HttpServlet{//存儲對應(yīng)的配置文件信息(config.properties)private static ConcurrentHashMap<String, String> initParams = new ConcurrentHashMap<String, String>();//ioc容器:實例化classprivate static ConcurrentHashMap<String, Object> iocMap = new ConcurrentHashMap<String, Object>();//存儲url和對應(yīng)的方法的Mapping關(guān)系private static ConcurrentHashMap<Pattern, MethodMapping> urlMethodMap = new ConcurrentHashMap<Pattern, MethodMapping>();//存儲掃描到的包路徑下class類private static List<Class<?>> classes = new ArrayList<>();@Overridepublic void init(ServletConfig servletConfig) throws ServletException {//1.根據(jù)web.xml配置的init-param獲取配置文件路徑,讀取掃包路徑parseConfig(servletConfig);//2.根據(jù)掃包路徑,遞歸獲取到所有需要掃描的class[]doScanner(initParams.get(Constants.PACKAGE_SCANNING));//3.初始化@CPService和@CPController的beans,放入到IOC容器中initBeans(classes);//4.對使用了@CPAutowire注解的屬性值進行依賴注入(反射機制)doDI();//5.遍歷所有的@CPController的類和其上的方法,對url和method進行映射handlerMapping();System.out.println("spring 啟動加載完成...........");}private void parseConfig(ServletConfig servletConfig) {String location = servletConfig.getInitParameter(Constants.CONTEXT_CONFIG_LOCATION);InputStream in = this.getClass().getClassLoader().getResourceAsStream(location);Properties properties = new Properties();try {properties.load(in);} catch (IOException e) {e.printStackTrace();}finally{try {if(in != null){in.close();}} catch (IOException e) {e.printStackTrace();}}//遍歷properties,保存到initParamMap里for(Object key:properties.keySet()){Object value = properties.get(key);initParams.put(key.toString(), value.toString());}}private void doScanner(String packageName) {//根據(jù)path遍歷所有class文件URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.","/"));File dir = new File(url.getFile());try{for(File file:dir.listFiles()){if(file.isDirectory()){//file是目錄,遞歸doScanner(packageName + "." + file.getName());}else{//獲取class文件路徑和文件名String className = packageName + "." + file.getName().replace(".class", "").trim();Class<?> classFile = Class.forName(className);classes.add(classFile);}}}catch (Exception e){}}private void initBeans(List<Class<?>> classes){try{//遍歷所有的class文件,判斷其上是否有CPController和CPService注解for(Class<?> clazz :classes){//對于CPController只需要存儲beanName和對應(yīng)bean的關(guān)系即可(一般不用于注入)if(clazz.isAnnotationPresent(CPController.class)){CPController controller = clazz.getAnnotation(CPController.class);String beanName = controller.value();//如果有定義屬性值,以其為beanName,否則默認類名首字母小寫if(StringUtils.isEmpty(beanName)){beanName = StringUtils.toFirstLowChar(clazz.getSimpleName());}iocMap.put(beanName, clazz.newInstance());continue;}else if(clazz.isAnnotationPresent(CPService.class)){//CPService注入有根據(jù)beanName和類型兩種(接口類型)CPService service = clazz.getAnnotation(CPService.class);String beanName = service.value();//如果有定義屬性值,以其為beanName,否則默認類名首字母小寫if(StringUtils.isEmpty(beanName)){beanName = StringUtils.toFirstLowChar(clazz.getSimpleName());iocMap.put(beanName, clazz.newInstance());}//按照類型存儲一個實例關(guān)系(為了方便按照類型注入)iocMap.put(clazz.getName(), clazz.newInstance());//按照接口的類型再存儲一個實例關(guān)系(注入的時候方便按照接口類型來注入)Class<?>[] interfaces = clazz.getInterfaces();for (Class<?> i : interfaces) {iocMap.put(i.getName(), clazz.newInstance());}}//TODO ...其他關(guān)于Component的注解就先不考慮}}catch (Exception e){}}//執(zhí)行依賴注入private void doDI() {try{//遍歷所有iocMap里的實例集合,判斷其屬性字段上是否有@CPAutowire注解for(Map.Entry<String,Object> entry:iocMap.entrySet()){Class<?> clazz = entry.getValue().getClass();Field[] fields = clazz.getDeclaredFields();for(Field field:fields){//CPAutowire默認使用byType的方式裝配CPAutowire autoAnnotation = field.getAnnotation(CPAutowire.class);field.setAccessible(true);if(autoAnnotation != null ){CPQualifier qualifier = field.getAnnotation(CPQualifier.class);if(qualifier != null && !StringUtils.isEmpty(qualifier.value())){//按照名字注入field.set(entry.getValue(), iocMap.get(qualifier.value()));continue;}//否則按照類型注入field.set(entry.getValue(), iocMap.get(field.getType().getName()));}}}}catch (Exception e){}}private void handlerMapping() {for(Map.Entry<String,Object> entry:iocMap.entrySet()){Class<?> clazz = entry.getValue().getClass();//判斷Controller類上是否有CPRequestMapping注解if(!clazz.isAnnotationPresent(CPRequestMapping.class)) continue;String baseUrl = clazz.getAnnotation(CPRequestMapping.class).value();Method[] methods = clazz.getDeclaredMethods();//遍歷CPController上的Method 獲取url與MethodMapping的映射關(guān)系for(Method method:methods){String methodUrl ="";if(method.isAnnotationPresent(CPRequestMapping.class)){methodUrl = method.getAnnotation(CPRequestMapping.class).value();}String regex = ("/"+baseUrl+methodUrl).replaceAll("/+", "/");Pattern pattern = Pattern.compile(regex);MethodMapping model = new MethodMapping(entry.getValue(),method);urlMethodMap.put(pattern, model);}}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {try{this.doDispatcher(req, resp);}catch (Exception e){resp.getWriter().write("500 Exception,Details:\r\n" + Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]", "").replaceAll(",\\s", "\r\n"));}}private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws Exception {//獲取實際的url請求String url = req.getRequestURI();String contextPath = req.getContextPath();url = url.replace(contextPath, "").replaceAll("/+", "/");//根據(jù)url請求去獲取響應(yīng)的MethodBean對象MethodMapping methodMapping = null;for(Pattern pattern: urlMethodMap.keySet()){if(pattern.matcher(url).matches()){methodMapping = urlMethodMap.get(pattern);}}//如果找不到匹配的url,則直接返回404if(methodMapping == null){resp.getWriter().println("404 not found");resp.flushBuffer();return;}//獲取方法的參數(shù)類型 列表Class<?> [] paramTypes = methodMapping.getMethod().getParameterTypes();//用于存儲實際的參數(shù)列表Object [] paramValues = new Object[paramTypes.length];//獲取請求的參數(shù)列表(Request請求里的參數(shù)都是字符串類型的,如果一個參數(shù)出現(xiàn)多次,那么它的value就是String數(shù)組)Map<String,String[]> params = req.getParameterMap();for (Map.Entry<String, String[]> param : params.entrySet()) {//將數(shù)組參數(shù)轉(zhuǎn)化為stringString value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");//如果找到匹配的參數(shù)名,則開始填充參數(shù)數(shù)組paramValuesif(!methodMapping.getParamIndexMapping().containsKey(param.getKey())){continue;}int index = methodMapping.getParamIndexMapping().get(param.getKey());paramValues[index] = convert(paramTypes[index],value);}//設(shè)置方法中的request和response對象if(methodMapping.getParamIndexMapping().containsKey(HttpServletRequest.class.getName())){int reqIndex = methodMapping.getParamIndexMapping().get(HttpServletRequest.class.getName());paramValues[reqIndex] = req;}if(methodMapping.getParamIndexMapping().containsKey(HttpServletResponse.class.getName())) {int respIndex = methodMapping.getParamIndexMapping().get(HttpServletResponse.class.getName());paramValues[respIndex] = resp;}//執(zhí)行方法獲得返回值Object returnValue = "";try {returnValue = methodMapping.getMethod().invoke(methodMapping.getController(),paramValues);//如果方法有加CPResponseBody注解,則直接返回結(jié)果 TODO Controller上也可加,這里就沒考慮這種情形if(methodMapping.getMethod().isAnnotationPresent(CPResponseBody.class)){resp.getWriter().println(returnValue);return;}//否則根據(jù)配置文件里配置的視圖進行轉(zhuǎn)發(fā)req.getRequestDispatcher(initParams.get(Constants.PAGE_PREFIX)+returnValue+initParams.get(Constants.PAGE_SUFFIX)).forward(req, resp);} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}/*** 轉(zhuǎn)化參數(shù)類型,將String轉(zhuǎn)化為實際的參數(shù)類型* */private Object convert(Class<?> paramType, String value) {if( int.class == paramType || Integer.class == paramType){return Integer.valueOf(value);}if( double.class == paramType || Double.class == paramType){return Double.valueOf(value);}//TODO 這里只是列舉了幾種常用的,可以繼續(xù)完善...return value;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {this.doPost(req,resp);} } public class MethodMapping {private Method method;private Object controller;protected Map<String,Integer> paramIndexMapping; //參數(shù)順序public Method getMethod() {return method;}public void setMethod(Method method) {this.method = method;}public Object getController() {return controller;}public void setController(Object controller) {this.controller = controller;}public Map<String, Integer> getParamIndexMapping() {return paramIndexMapping;}public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {this.paramIndexMapping = paramIndexMapping;}public MethodMapping(Object controller, Method method){this.controller = controller;this.method = method;paramIndexMapping = new HashMap<String,Integer>();putParamIndexMapping(method);}/*** 根據(jù)方法獲取對應(yīng)參數(shù)和下標的Mapping** */private void putParamIndexMapping(Method method) {//遍歷Method中的所有參數(shù),獲取其對應(yīng)的參數(shù)名和下標Parameter[] params = method.getParameters();for(int i = 0 ; i < params.length ; i++){Class<?> type = params[i].getType();if(type == HttpServletRequest.class || type == HttpServletResponse.class){paramIndexMapping.put(type.getName(),i);continue;}Annotation[] annotations = params[i].getAnnotations();String paramName = getAnnotationParamName(annotations);if(StringUtils.isEmpty(paramName)){//想要通過反射獲取參數(shù)名而不是arg0,需要在編譯時指定“-parameters”選項paramName = params[i].getName();}paramIndexMapping.put(paramName,i);}}private String getAnnotationParamName(Annotation[] annotations){for(Annotation a : annotations) {if (a instanceof CPRequestParam) {return ((CPRequestParam) a).value();}}return "";}}

執(zhí)行效果:



源碼地址:
https://github.com/dearfulan/cp-springmvc/tree/master/

總結(jié)

以上是生活随笔為你收集整理的手写实现Spring(IOC、DI),SpringMVC基础功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。