代码实现SpringMvc

  偶然看到一篇100多行实现SpringMvc的博客,阅读后整理加实现出来。大家共勉!(纸上得来终觉浅,绝知此事要躬行。)

  实现Spring的部分。

  1. Bean工厂,统一创建Bean;
  2. IOC,实现Bean的依赖注入;
  3. DispatchServlet,SpringMVC的路径映射。

  代码解析如下:

  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

猜你喜欢

转载自www.cnblogs.com/chewq/p/10165497.html