您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“SSM框架的示例分析”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“SSM框架的示例分析”這篇文章吧。
SSM圖示流程:
Spring核心:Java反射
Mybatis:動(dòng)態(tài)代理,而動(dòng)態(tài)代理又是基于反射的,所以,ssm框架核心原理在反射。
(1)Spring(對(duì)象工廠(chǎng)): 平時(shí)開(kāi)發(fā)接觸最多的估計(jì)就是這個(gè)IOC容器,它可以裝載bean(也就是Java中的類(lèi),當(dāng)然也包括service、dao里面的),有了這個(gè)機(jī)制,就不用在每次使用這個(gè)類(lèi)的時(shí)候?yàn)樗跏蓟苌倏吹疥P(guān)鍵字new。
(2)SpringMVC(視圖控制器): 核心為一個(gè)DispatcherServlet,控制所有請(qǐng)求
這里奉上手寫(xiě)SpringMVC的核心DispatcherServlet源碼
package servlet; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import annotation.HController; import annotation.HRequestMapping; /** * 手寫(xiě)SpringMVC * * @author hxz * @description TODO * @data 2020年1月2日 上午9:39:57 */ public class MyDispatcherServlet extends HttpServlet { //加載屬性文件 private Properties properties = new Properties(); //裝載beanname private List<String> classNames = new ArrayList<String>(); //ioc容器 private Map<String, Object> ioc = new HashMap<String, Object>(); //類(lèi)似于以前自定義的cache緩存容器,這里也是起到一個(gè)容器的作用 //用于加載各個(gè)mapping private Map<String, Method> handlerMapping = new HashMap<String, Method>(); //容器加載所有的controller private Map<String, Object> controllerMap = new HashMap<String, Object>(); @Override public void init(ServletConfig config) throws ServletException { // 1.加載配置文件 doLoadConfig(config.getInitParameter("contextConfigLocation")); // 2.初始化所有相關(guān)聯(lián)的類(lèi),掃描用戶(hù)設(shè)定的包下面所有的類(lèi) doScanner(properties.getProperty("scanPackage")); // 3.拿到掃描到的類(lèi),通過(guò)反射機(jī)制,實(shí)例化,并且放到ioc容器中beanName默認(rèn)是首字母小寫(xiě) doInstance(); // 4.初始化HandlerMapping(將url和method對(duì)應(yīng)上) initHandlerMapping(); } @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 { // 處理請(qǐng)求 doDispatch(req, resp); } catch (Exception e) { resp.getWriter().write("500!! Server Exception"); } } private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { if (handlerMapping.isEmpty()) { return; } String url = req.getRequestURI(); String contextPath = req.getContextPath(); url = url.replace(contextPath, "").replaceAll("/+", "/"); if (!this.handlerMapping.containsKey(url)) { resp.getWriter().write("404 NOT FOUND!"); return; } Method method = this.handlerMapping.get(url); // 獲取方法的參數(shù)列表 Class<?>[] parameterTypes = method.getParameterTypes(); // 獲取請(qǐng)求的參數(shù) Map<String, String[]> parameterMap = req.getParameterMap(); // 保存參數(shù)值 Object[] paramValues = new Object[parameterTypes.length]; // 方法的參數(shù)列表 for (int i = 0; i < parameterTypes.length; i++) { // 根據(jù)參數(shù)名稱(chēng),做某些處理 String requestParam = parameterTypes[i].getSimpleName(); if (requestParam.equals("HttpServletRequest")) { // 參數(shù)類(lèi)型已明確,這邊強(qiáng)轉(zhuǎn)類(lèi)型 paramValues[i] = req; continue; } if (requestParam.equals("HttpServletResponse")) { paramValues[i] = resp; continue; } if (requestParam.equals("String")) { for (Entry<String, String[]> param : parameterMap.entrySet()) { String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ","); paramValues[i] = value; } } } // 利用反射機(jī)制來(lái)調(diào)用 try { method.invoke(this.controllerMap.get(url), paramValues);// 第一個(gè)參數(shù)是method所對(duì)應(yīng)的實(shí)例 // 在ioc容器中 } catch (Exception e) { e.printStackTrace(); } } private void doLoadConfig(String location) { // 把web.xml中的contextConfigLocation對(duì)應(yīng)value值的文件加載到流里面 InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location); try { // 用Properties文件加載文件里的內(nèi)容 properties.load(resourceAsStream); } catch (IOException e) { e.printStackTrace(); } finally { // 關(guān)流 if (null != resourceAsStream) { try { resourceAsStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void doScanner(String packageName) { // 把所有的.替換成/ URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/")); File dir = new File(url.getFile()); for (File file : dir.listFiles()) { if (file.isDirectory()) { // 遞歸讀取包 doScanner(packageName + "." + file.getName()); } else { String className = packageName + "." + file.getName().replace(".class", ""); classNames.add(className); } } } //利用java的反射機(jī)制 private void doInstance() { if (classNames.isEmpty()) { return; } for (String className : classNames) { try { // 把類(lèi)搞出來(lái),反射來(lái)實(shí)例化 Class<?> clazz = Class.forName(className); if (clazz.isAnnotationPresent(HController.class)) { ioc.put(toLowerFirstWord(clazz.getSimpleName()), clazz.newInstance()); } else { continue; } } catch (Exception e) { e.printStackTrace(); continue; } } } private void initHandlerMapping() { if (ioc.isEmpty()) { return; } try { for (Entry<String, Object> entry : ioc.entrySet()) { Class<? extends Object> clazz = entry.getValue().getClass(); if (!clazz.isAnnotationPresent(HController.class)) { continue; } // 拼url時(shí),是controller頭的url拼上方法上的url String baseUrl = ""; if (clazz.isAnnotationPresent(HRequestMapping.class)) { HRequestMapping annotation = clazz.getAnnotation(HRequestMapping.class); baseUrl = annotation.value(); } Method[] methods = clazz.getMethods(); for (Method method : methods) { if (!method.isAnnotationPresent(HRequestMapping.class)) { continue; } HRequestMapping annotation = method.getAnnotation(HRequestMapping.class); String url = annotation.value(); url = (baseUrl + "/" + url).replaceAll("/+", "/"); handlerMapping.put(url, method); controllerMap.put(url, clazz.newInstance()); System.out.println(url + "," + method); } } } catch (Exception e) { e.printStackTrace(); } } /** * 把字符串的首字母小寫(xiě) * * @param name * @return */ private String toLowerFirstWord(String name) { char[] charArray = name.toCharArray(); charArray[0] += 32; return String.valueOf(charArray); } }
從源碼及可看出流程:
1)客戶(hù)端發(fā)送請(qǐng)求到DispacherServlet(由web.xml攔截所有請(qǐng)求到改servlet);
2)由DispacherServlet(核心servlet)控制器查詢(xún)HanderMapping,找到處理請(qǐng)求的Controller;(這里我用了一個(gè)map類(lèi)似于緩存容器,裝載所有的mapping即映射)
3)Controller層調(diào)用業(yè)務(wù)邏輯處理后,返回ModelAndView,即下一層(往往是service、serviceimpl,mapper層)返回的的數(shù)據(jù);
4)DispacherSerclet查詢(xún)視圖解析器,找到ModelAndView指定的視圖;
5)視圖負(fù)責(zé)將結(jié)果顯示到客戶(hù)端。
(3)Mybatis(持久層框架):mybatis是對(duì)jdbc的封裝,它讓數(shù)據(jù)庫(kù)底層操作變的透明。mybatis的操作都是圍繞一個(gè)sqlSessionFactory實(shí)例展開(kāi)的。mybatis通過(guò)配置文件關(guān)聯(lián)到各實(shí)體類(lèi)的Mapper文件,Mapper文件中配置了每個(gè)類(lèi)對(duì)數(shù)據(jù)庫(kù)所需進(jìn)行的sql語(yǔ)句映射。在每次與數(shù)據(jù)庫(kù)交互時(shí),通過(guò)sqlSessionFactory拿到一個(gè)sqlSession,再通過(guò)得到Mapper文件sqlSession.getMapper()最后調(diào)用的是JDK的動(dòng)態(tài)代理(exlipse一直Ctrl+鼠標(biāo)左鍵點(diǎn)擊到最后發(fā)現(xiàn)如此,源碼附上)。
protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
發(fā)人員只需要?jiǎng)?chuàng)建Mapper接口,并使用Mapper接口即可。Mybatis會(huì)對(duì)Mapper接口產(chǎn)生動(dòng)態(tài)代理對(duì)象,這個(gè)動(dòng)態(tài)代理對(duì)象實(shí)現(xiàn)了Mapper接口,擁有Mapper中定義的所有方法,并對(duì)這些方法進(jìn)行了增強(qiáng)。增強(qiáng)的邏輯是獲得sql語(yǔ)句和執(zhí)行sql語(yǔ)句。
動(dòng)態(tài)代理:
通過(guò)實(shí)現(xiàn) InvocationHandler 接口創(chuàng)建自己的調(diào)用處理器;
通過(guò)為 Proxy 類(lèi)指定 ClassLoader 對(duì)象和一組 interface 來(lái)創(chuàng)建動(dòng)態(tài)代理類(lèi);
通過(guò)反射機(jī)制獲得動(dòng)態(tài)代理類(lèi)的構(gòu)造函數(shù),其唯一參數(shù)類(lèi)型是調(diào)用處理器接口類(lèi)型;
通過(guò)構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例,構(gòu)造時(shí)調(diào)用處理器對(duì)象作為參數(shù)被傳入。
框架核心原理
AOP 面向切面編程(AOP)提供另外一種角度來(lái)思考程序結(jié)構(gòu),通過(guò)這種方式彌補(bǔ)了面向?qū)ο缶幊蹋∣OP)的不足。除了類(lèi)(classes)以外,AOP提供了切面。切面對(duì)關(guān)注點(diǎn)進(jìn)行模塊化,例如橫切多個(gè)類(lèi)型和對(duì)象的事務(wù)管理。Spring的一個(gè)關(guān)鍵的組件就是AOP框架,可以自由選擇是否使用AOP。提供聲明式企業(yè)服務(wù),特別是為了替代EJB聲明式服務(wù)。最重要的服務(wù)是聲明性事務(wù)管理,這個(gè)服務(wù)建立在Spring的抽象事物管理之上。允許用戶(hù)實(shí)現(xiàn)自定義切面,用AOP來(lái)完善OOP的使用可以把Spring AOP看作是對(duì)Spring的一種增強(qiáng)。AOP的實(shí)現(xiàn)乃至spring框架基本上核心代碼都是基于Java語(yǔ)言的反射機(jī)制(所謂的反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制。)。
AOP主要作用就是不通過(guò)修改源代碼的方式、將非核心功能代碼織入來(lái)實(shí)現(xiàn)對(duì)方法的增強(qiáng)。那么Spring AOP的底層如何實(shí)現(xiàn)對(duì)方法的增強(qiáng)?實(shí)現(xiàn)的關(guān)鍵在于使用了代理模式。代理模式的作用就是為其它對(duì)象提供一種代理,以控制對(duì)這個(gè)對(duì)象的訪(fǎng)問(wèn),用于解決在直接訪(fǎng)問(wèn)對(duì)象時(shí)帶來(lái)的各種問(wèn)題,比如要訪(fǎng)問(wèn)的對(duì)象在遠(yuǎn)程的機(jī)器上。在面向?qū)ο笙到y(tǒng)中,由于其他某些原因(對(duì)象創(chuàng)建開(kāi)銷(xiāo)很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪(fǎng)問(wèn))等
代理主要分為兩種方式:靜態(tài)代理和動(dòng)態(tài)代理
IOC IoC不是一種技術(shù),只是一種思想,一個(gè)重要的面向?qū)ο缶幊痰姆▌t,它能指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序。有了IoC容器后,把創(chuàng)建和查找依賴(lài)對(duì)象的控制權(quán)交給了容器,由容器進(jìn)行注入組合對(duì)象,所以相較于傳統(tǒng)的java servlet需要自己request.getParamiter等需要一系列取值,轉(zhuǎn)換中文,轉(zhuǎn)換值類(lèi)型的繁瑣,更重要的是使得程序的整個(gè)體系結(jié)構(gòu)變得非常靈活。
自定義一個(gè)IOC容器的思路:
Map做一個(gè)容器,然后用解析xml文件的工具解析出需要掃描的包。利用Java反射機(jī)制拿到鎖具有的方法,屬性,注入到Map容器中
DI 依賴(lài)注入,是組件之間依賴(lài)關(guān)系由容器在運(yùn)行期決定,形象的說(shuō),即由容器動(dòng)態(tài)地將某個(gè)依賴(lài)關(guān)系注入到組件之中。依賴(lài)注入的目的并非為軟件系統(tǒng)帶來(lái)更多功能,而是為了提升組件重用的頻率,并為系統(tǒng)搭建一個(gè)靈活、可擴(kuò)展的平臺(tái)。通過(guò)依賴(lài)注入機(jī)制,我們只需要通過(guò)簡(jiǎn)單的配置,而無(wú)需任何代碼就可指定目標(biāo)需要的資源,完成自身的業(yè)務(wù)邏輯,而不需要關(guān)心具體的資源來(lái)自何處,由誰(shuí)實(shí)現(xiàn)。
以上是“SSM框架的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。