源碼學習(一)——模擬Spring MVC
1.準備
1.1創建項maven項目,目錄如下
1.2 導包
servlet-api: 模擬springmvc采用的是對同一個servlet進行處理
fastjson: JSONObject 是阿裏自己封裝的一個map,本人習慣使用,非必需
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.rrg</groupId> <artifactId>learning-framework</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies> </project>
2.自定義SpringMVC註解
2.1 MyMapper
package com.rrg.ssm.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; @Target(ElementType.TYPE) //作用目標 所有對象 @Retention(RetentionPolicy.RUNTIME) //保留策略 運行期 @Documented public @interface MyMapper { String value() default ""; }
2.2MyService.java
package com.rrg.ssm.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;
@Target(ElementType.TYPE) //作用目標 所有對象
@Retention(RetentionPolicy.RUNTIME) //保留策略 運行期
@Documented
public @interface MyService {
String value() default "";
}
2.2
package com.rrg.ssm.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; @Target(ElementType.TYPE) //作用目標 所有對象 @Retention(RetentionPolicy.RUNTIME) //保留策略 運行期 @Documented public @interface MyController { String value() default ""; }
2.3MyController.java
package com.rrg.ssm.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; @Target(ElementType.TYPE) //作用目標 所有對象 @Retention(RetentionPolicy.RUNTIME) //保留策略 運行期 @Documented public @interface MyController { String value() default ""; }
2.4 MyQulifier.java
package com.rrg.ssm.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; @Target(ElementType.FIELD) //作用目標 字段 即 成員變量 @Retention(RetentionPolicy.RUNTIME) //保留策略 運行期 @Documented public @interface MyQulifier { String value() default ""; }
2.5 RequestMapping.java
package com.rrg.ssm.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; @Target({ElementType.TYPE,ElementType.METHOD}) //作用目標 所有對象 和 方法 @Retention(RetentionPolicy.RUNTIME) //保留策略 運行期 @Documented public @interface MyRequestMapping { String value() default ""; }
3.模擬業務邏輯
3.1 entity
User.java
package com.rrg.ssm.entity; public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [name=" + name + ", age=" + age + "]"; } }
3.2 mapper層
UserMapper.java
package com.rrg.ssm.mapper; import com.rrg.ssm.annotation.MyMapper; import com.rrg.ssm.entity.User; /** * 用戶Mapper * @author JIE */ @MyMapper("userMapper") public class UserMapper { public User selectById(Integer id){ System.out.println("【UserMapper】執行查詢操作"); User user = new User("JIE", 22); return user; } }
3.3 service層
UserSservice.java
package com.rrg.ssm.service; import com.rrg.ssm.entity.User; /** * 用戶服務接口 * @author JIE */ public interface UserService { /** * 根據id查找用戶 */ public User selectById(Integer id); }
UserServiceImpl.java
package com.rrg.ssm.service.impl; import com.rrg.ssm.annotation.MyQulifier; import com.rrg.ssm.annotation.MyService; import com.rrg.ssm.entity.User; import com.rrg.ssm.mapper.UserMapper; import com.rrg.ssm.service.UserService; /** * 用戶服務實現類 * @author JIE */ @MyService("userService") public class UserServiceImpl implements UserService { @MyQulifier("userMapper") private UserMapper userMapper; public User selectById(Integer id) { System.out.println("【UserService】執行業務操作"); return userMapper.selectById(id); } }
3.4 UserController.java
package com.rrg.ssm.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.rrg.ssm.annotation.MyController; import com.rrg.ssm.annotation.MyQulifier; import com.rrg.ssm.annotation.MyRequestMapping; import com.rrg.ssm.entity.User; import com.rrg.ssm.service.UserService; /** * * @author JIE * */ @MyController("userController") @MyRequestMapping("/user") public class UserController { @MyQulifier("userService") private UserService userService; @MyRequestMapping("/get") public void getUser(HttpServletRequest request, HttpServletResponse response) { User user = userService.selectById(2); System.out.println("【UserController】:" + user); } }
4.spring mvc核心
思路: ①掃描包,將所有文件放到package的一個list裏面;
②掃描①中的包,找到三層架構的controller,service,mapper並實例化放到map,key為註解上的值就變量名,例如@MyController("userController") map("userController",userController實例化的對象);
③建立映射關系,實現@RequestMapping功能,根據類前的註解和方法前的註解,保存到map,key是攔截的地址,value是對應的方法,為後面提供調 用method.invoke(userController, req, resp);
④註入依賴,DI,根據MyQulifier註解到②的map中找到實體,註入到成員變量 field(obj,obj)
4.1 核心MyDispatcherServlet.java
package com.rrg.ssm.core; 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.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; import com.alibaba.fastjson.JSONObject; import com.rrg.ssm.annotation.MyController; import com.rrg.ssm.annotation.MyMapper; import com.rrg.ssm.annotation.MyQulifier; import com.rrg.ssm.annotation.MyRequestMapping; import com.rrg.ssm.annotation.MyService; import com.rrg.ssm.controller.UserController; /** * Spring MVC核心 * @author JIE */ public class MyDispatcherServlet extends HttpServlet { private static final long serialVersionUID = 1L; private List<String> packageList = new ArrayList<String>(); private JSONObject instanceJSON = new JSONObject(); private JSONObject mappingJSON = new JSONObject(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //requestURl=> http://localhost:8180/learning-again/user/get //StringBuffer requestURl = req.getRequestURL(); //requestURI=> /learning-again/user/get String requestURI = req.getRequestURI(); //contextPath=> /learning-again String contextPath = req.getContextPath(); //reqpath=> /user/get String reqpath = requestURI.replace(contextPath, ""); UserController userController = (UserController) instanceJSON.get("userController"); Method method = (Method) mappingJSON.get(reqpath); try {//攔截請求找到實例對象的方法,並調用 method.invoke(userController, req, resp); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } @Override public void init(ServletConfig config) throws ServletException { // 包掃描,獲取包中的文件 scanPackage("com.rrg"); System.out.println("【init】掃描包完成"); try { filterAndInstance(); System.out.println("【init】實例化(註解)完成"); } catch (Exception e) { e.printStackTrace(); } // 建立映射關系 handerMap(); System.out.println("【init】映射完成"); // 實現註入 DI(); System.out.println("【init】屬性註入完成"); } /** * 掃描字段註解 */ private void DI() { if(instanceJSON.size() <= 0) { return ; } for (Map.Entry<String, Object> entry : instanceJSON.entrySet()) { Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { if(field.isAnnotationPresent(MyQulifier.class)) { MyQulifier myQulifier = field.getAnnotation(MyQulifier.class); String key = myQulifier.value(); field.setAccessible(true); try { field.set(entry.getValue(), instanceJSON.get(key)); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } /** * requestMapping */ private void handerMap() { for (Map.Entry<String, Object> entry : instanceJSON.entrySet()) { if(entry.getValue().getClass().isAnnotationPresent(MyController.class)) { MyRequestMapping myRequestMapping = entry.getValue().getClass().getAnnotation(MyRequestMapping.class); String classMapping = myRequestMapping.value(); //取得所有在 Method[] methods = entry.getValue().getClass().getDeclaredMethods(); for (Method method : methods) { if(method.isAnnotationPresent(MyRequestMapping.class)) { MyRequestMapping methodRequestMapping = method.getAnnotation(MyRequestMapping.class); String methodMapping = methodRequestMapping.value(); mappingJSON.put(classMapping + methodMapping , method); }else { continue; } } } } } /** * 實例化三層架構的實例化 */ private void filterAndInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException { //instanceJSON if(packageList.size()<=0) { return ; } for (String filePackage : packageList) { Class<?> fileClass = Class.forName(filePackage.replace(".class", "").trim()); //判斷類是否存在註釋 if(fileClass.isAnnotationPresent(MyController.class)) { Object newInstance = fileClass.newInstance(); MyController myController = newInstance.getClass().getAnnotation(MyController.class); String key = myController.value(); instanceJSON.put(key,newInstance); }else if(fileClass.isAnnotationPresent(MyService.class)) { Object newInstance = fileClass.newInstance(); MyService myService = newInstance.getClass().getAnnotation(MyService.class); String key = myService.value(); instanceJSON.put(key,newInstance); }else if(fileClass.isAnnotationPresent(MyMapper.class)) { Object newInstance = fileClass.newInstance(); MyMapper myMapper = newInstance.getClass().getAnnotation(MyMapper.class); String key = myMapper.value(); instanceJSON.put(key,newInstance); }else { continue; } } } private void scanPackage(String PACKAGE) { // file:/C:/Users/abc/eclipse_0821/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/learning-again/WEB-INF/classes/com/rrg/ URL url=this.getClass().getClassLoader().getResource("/" + replaceTo(PACKAGE)); // /C:/Users/abc/eclipse_0821/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/learning-again/WEB-INF/classes/com/rrg/ String fileName = url.getFile(); File file = new File(fileName); String[] list = file.list(); for (String path : list) { File eachFile = new File(fileName + path); if(eachFile.isDirectory()) { scanPackage(PACKAGE + "." + eachFile.getName()); }else { packageList.add(PACKAGE + "." + eachFile.getName()); } } } /** * path中‘.‘轉成‘/‘ */ private String replaceTo(String path) { return path.replaceAll("\\.", "/"); } }
4.2 統一處理請求
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>aaaa</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>MyDispatcherServlet</servlet-name> <servlet-class>com.rrg.ssm.core.MyDispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyDispatcherServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
5 測試
DEBUG AS=》 SERVER 訪問 http://localhost:8080/user/get,
控制臺打印
SUCCESS!
以上的源碼借鑒博客 https://www.cnblogs.com/Shock-W/p/6617068.html
源碼學習(一)——模擬Spring MVC