SSM process in layman's language framework and principles

Introduction: Learning ssm framework has been a long time, today to review the
SSM icon process:
Here Insert Picture Description
(1) the Spring (Object Factory): usually develop the most contact is estimated that the IOC container, it can be loaded bean (that is, in Java class, of course, including service,), with this mechanism dao inside, it would not have to initialize each time using this class, you rarely see the keyword new.
(2) SpringMVC (View Controller): The core is a DispatcherServlet, controls all requests
served here handwritten SpringMVC core source 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;

/**
 * 手写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>();
    //类似于以前自定义的cache缓存容器,这里也是起到一个容器的作用
    //用于加载各个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.初始化所有相关联的类,扫描用户设定的包下面所有的类
		doScanner(properties.getProperty("scanPackage"));

		// 3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中beanName默认是首字母小写
		doInstance();

		// 4.初始化HandlerMapping(将url和method对应上)
		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 {
			// 处理请求
			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);

		// 获取方法的参数列表
		Class<?>[] parameterTypes = method.getParameterTypes();

		// 获取请求的参数
		Map<String, String[]> parameterMap = req.getParameterMap();

		// 保存参数值
		Object[] paramValues = new Object[parameterTypes.length];

		// 方法的参数列表
		for (int i = 0; i < parameterTypes.length; i++) {
			// 根据参数名称,做某些处理
			String requestParam = parameterTypes[i].getSimpleName();

			if (requestParam.equals("HttpServletRequest")) {
				// 参数类型已明确,这边强转类型
				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;
				}
			}
		}
		// 利用反射机制来调用
		try {
			method.invoke(this.controllerMap.get(url), paramValues);// 第一个参数是method所对应的实例
																	// 在ioc容器中
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void doLoadConfig(String location) {
		// 把web.xml中的contextConfigLocation对应value值的文件加载到流里面
		InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location);
		try {
			// 用Properties文件加载文件里的内容
			properties.load(resourceAsStream);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关流
			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的反射机制
	private void doInstance() {
		if (classNames.isEmpty()) {
			return;
		}
		for (String className : classNames) {
			try {
				// 把类搞出来,反射来实例化
				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时,是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();
		}

	}

	/**
	 * 把字符串的首字母小写
	 * 
	 * @param name
	 * @return
	 */
	private String toLowerFirstWord(String name) {
		char[] charArray = name.toCharArray();
		charArray[0] += 32;
		return String.valueOf(charArray);
	}

}

As can be seen from the source and processes:
1) The client sends a request to DispacherServlet (a change web.xml intercepts all requests to the servlet);

2) a query DispacherServlet (Core the servlet) controller HanderMapping, find Controller processing request; (I used here is similar to a cache map container, i.e. the loading of all mapping maps)

3) Controller layer was invoked service logic processing returns ModelAndView, i.e., the next layer (often the service, serviceimpl, mapper layer) of data returned;

4) DispacherSerclet query view resolver, find ModelAndView specified view;

5) view is responsible for displaying the results to the client.
(3) Mybatis (persistence framework) : encapsulation of jdbc MyBatis is, it allows the underlying database operation becomes transparent. mybatis operations are built around a sqlSessionFactory instance unfolded. File Mapper mybatis associated to each entity class by the configuration file, the configuration file Mapper sql statement required to map each type of database performed. Every time you interact with the database through sqlSessionFactory get a sqlSession, then by getting Mapper file sqlSession.getMapper last call is () JDK dynamic proxy (exlipse been Ctrl + left mouse button click to find the last of this, the source code attached) .

  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);

Developers only need to create Mapper interface and the interface can use Mapper. Mybatis will Mapper interface to generate dynamic proxy objects, the dynamic proxy object is achieved Mapper interfaces with all the methods defined in Mapper, and these methods have been enhanced. Enhanced logic is to obtain and execute the sql statement sql statement.

Framework Core Principle

  1. AOP Aspect Oriented Programming (AOP) provide another of thinking about program structure in this way to make up for the shortage of object-oriented programming (OOP) is. In addition to class (classes), AOP gives a cut. Cut the face of concerns modular, such as cross-transaction management and multiple types of objects. Spring is a critical component is the AOP framework, are free to choose whether to use AOP. To provide declarative enterprise services, especially as a replacement for EJB declarative services. The most important such service is declarative transaction management, which builds on Spring's management abstract things. It allows users to implement custom aspects of OOP with AOP to improve the use of Spring AOP can be seen as an enhancement to the Spring. AOP to achieve substantially even spring framework is based on the core code language Java reflection mechanism (so-called reflection is in the operating state, for any class, this class can know all the properties and methods ; for any one object, it can invoke any of the methods and properties ; this dynamic access to information and dynamic method call object functions called java language reflection mechanism).
  2. IOC IoC is not a technology, but an idea, an important rule of object-oriented programming that guides how we design a loosely coupled, better program. Once you have IoC container to create and find dependent objects of control to the container, composite objects are implanted by the container, so compared to traditional java servlet needs its own request.getParamiter that require a series of values, convert Chinese, conversion value type of complicated, more important is the structure of the program makes the whole system becomes very flexible.
  3. DI dependency injection, is dependent on the relationship between components at runtime is determined by the vessel, said the image that dynamically inject the dependencies into a container assembly. Dependency injection is not intended to bring more functionality to software systems, but to enhance component reuse frequencies, and for the system to build a flexible, scalable platform. Via dependency injection mechanism, we need only a simple configuration, without any code can specify the target resources needed to complete their business logic without having to be concerned about the specific resources come from, who to achieve.
Released nine original articles · won praise 73 · views 8735

Guess you like

Origin blog.csdn.net/AAAhxz/article/details/103799107