偶然看到一篇100多行实现SpringMvc的博客,阅读后整理加实现出来。大家共勉!(纸上得来终觉浅,绝知此事要躬行。)
实现Spring的部分。
代码解析如下:
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
原文:https://www.cnblogs.com/chewq/p/10165497.html