123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- package cn.nosum.framework.mvc.v3.servlet;
- import cn.nosum.framework.annotation.*;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.net.URL;
- import java.util.*;
- public class GPDispatcherServlet extends HttpServlet {
- //保存application.properties配置文件中的内容
- private Properties contextConfig = new Properties();
- //保存扫描的所有的类名
- private List<String> classNames = new ArrayList<String>();
- // IOC容器
- private Map<String, Object> ioc = new HashMap<String, Object>();
- // 保存url和Method的对应关系
- private List<Handler> handlerMapping = new ArrayList<Handler>();
- @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 {
- //6、调用,运行阶段
- try {
- doDispatch(req, resp);
- } catch (Exception e) {
- e.printStackTrace();
- resp.getWriter().write("500 Exection,Detail : " + Arrays.toString(e.getStackTrace()));
- }
- }
- private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
- Handler handler = getHandler(req);
- if (handler == null) {
- resp.getWriter().write("404 Not Found!!!");
- return;
- }
- //获得方法的形参列表
- Class<?>[] paramTypes = handler.getParamTypes();
- Object[] paramValues = new Object[paramTypes.length];
- Map<String, String[]> params = req.getParameterMap();
- for (Map.Entry<String, String[]> parm : params.entrySet()) {
- String value = Arrays.toString(parm.getValue())
- .replaceAll("\\[|\\]", "")
- .replaceAll("\\s", ",");
- if (!handler.paramIndexMapping.containsKey(parm.getKey())) {
- continue;
- }
- int index = handler.paramIndexMapping.get(parm.getKey());
- paramValues[index] = convert(paramTypes[index], value);
- }
- if (handler.paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
- int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());
- paramValues[reqIndex] = req;
- }
- if (handler.paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
- int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());
- paramValues[respIndex] = resp;
- }
- Object returnValue = handler.method.invoke(handler.controller, paramValues);
- if (returnValue == null || returnValue instanceof Void) {
- return;
- }
- resp.getWriter().write(returnValue.toString());
- }
- private Handler getHandler(HttpServletRequest req) {
- if (handlerMapping.isEmpty()) {
- return null;
- }
- // 绝对路径
- String url = req.getRequestURI();
- // 处理成相对路径
- String contextPath = req.getContextPath();
- url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
- for (Handler handler : this.handlerMapping) {
- Matcher matcher = handler.getPattern().matcher(url);
- if (!matcher.matches()) {
- continue;
- }
- return handler;
- }
- return null;
- }
- //url传过来的参数都是String类型的,HTTP是基于字符串协议
- //只需要把String转换为任意类型就好
- private Object convert(Class<?> type, String value) {
- //如果是int
- if (Integer.class == type) {
- return Integer.valueOf(value);
- } else if (Double.class == type) {
- return Double.valueOf(value);
- }
- //如果还有double或者其他类型,继续加if
- //这时候,我们应该想到策略模式了
- //在这里暂时不实现,希望小伙伴自己来实现
- return value;
- }
- //初始化阶段
- @Override
- public void init(ServletConfig config) throws ServletException {
- //1、加载配置文件
- doLoadConfig(config.getInitParameter("contextConfigLocation"));
- //2、扫描相关的类
- doScanner(contextConfig.getProperty("scanPackage"));
- //3、初始化扫描到的类,并且将它们放入到ICO容器之中
- doInstance();
- //4、完成依赖注入
- doAutowired();
- //5、初始化HandlerMapping
- initHandlerMapping();
- System.out.println("Spring framework is init.");
- }
- //初始化url和Method的一对一对应关系
- private void initHandlerMapping() {
- if (ioc.isEmpty()) {
- return;
- }
- for (Map.Entry<String, Object> entry : ioc.entrySet()) {
- Class<?> clazz = entry.getValue().getClass();
- if (!clazz.isAnnotationPresent(Controller.class)) {
- continue;
- }
- //保存写在类上面的@GPRequestMapping("/demo")
- String baseUrl = "";
- if (clazz.isAnnotationPresent(RequestMapping.class)) {
- RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
- baseUrl = requestMapping.value();
- }
- //默认获取所有的 public方法
- for (Method method : clazz.getMethods()) {
- if (!method.isAnnotationPresent(RequestMapping.class)) {
- continue;
- }
- RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
- //优化
- String regex = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
- Pattern pattern = Pattern.compile(regex);
- this.handlerMapping.add(new Handler(pattern, entry.getValue(), method));
- System.out.println("Mapped :" + pattern + "," + method);
- }
- }
- }
- //自动依赖注入
- private void doAutowired() {
- if (ioc.isEmpty()) {
- return;
- }
- for (Map.Entry<String, Object> entry : ioc.entrySet()) {
- //Declared 所有的,特定的 字段,包括 private/protected/default
- //正常来说,普通的OOP编程只能拿到public的属性
- Field[] fields = entry.getValue().getClass().getDeclaredFields();
- for (Field field : fields) {
- if (!field.isAnnotationPresent(Autowired.class)) {
- continue;
- }
- Autowired autowired = field.getAnnotation(Autowired.class);
- //如果用户没有自定义beanName,默认就根据类型注入
- //这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业
- //小伙伴们自己去完善
- String beanName = autowired.value().trim();
- if ("".equals(beanName)) {
- //获得接口的类型,作为key待会拿这个key到ioc容器中去取值
- beanName = field.getType().getName();
- }
- //如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值
- //反射中叫做暴力访问, 强吻
- field.setAccessible(true);
- try {
- //用反射机制,动态给字段赋值
- field.set(entry.getValue(), ioc.get(beanName));
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- }
- private void doInstance() {
- //初始化,为DI做准备
- if (classNames.isEmpty()) {
- return;
- }
- try {
- for (String className : classNames) {
- Class<?> clazz = Class.forName(className);
- if (clazz.isAnnotationPresent(Controller.class)) {
- Object instance = clazz.newInstance();
- String beanName = toLowerFirstCase(clazz.getSimpleName());
- ioc.put(beanName, instance);
- } else if (clazz.isAnnotationPresent(Service.class)) {
- Service service = clazz.getAnnotation(Service.class);
- String beanName = service.value();
- if ("".equals(beanName.trim())) {
- beanName = toLowerFirstCase(clazz.getSimpleName());
- }
- Object instance = clazz.newInstance();
- ioc.put(beanName, instance);
- for (Class<?> i : clazz.getInterfaces()) {
- if (ioc.containsKey(i.getName())) {
- throw new Exception("The “" + i.getName() + "” is exists!!");
- }
- ioc.put(i.getName(), instance);
- }
- } else {
- continue;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- //扫描出相关的类
- private void doScanner(String scanPackage) {
- URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
- File classPath = new File(url.getFile());
- for (File file : classPath.listFiles()) {
- if (file.isDirectory()) {
- doScanner(scanPackage + "." + file.getName());
- } else {
- if (!file.getName().endsWith(".class")) {
- continue;
- }
- String className = (scanPackage + "." + file.getName().replace(".class", ""));
- classNames.add(className);
- }
- }
- }
- //加载配置文件
- private void doLoadConfig(String contextConfigLocation) {
- // 直接从类路径下找到Spring主配置文件所在的路径
- // 并且将其读取出来放到Properties对象中
- // 相对于scanPackage=cn.nosum.demo 从文件中保存到了内存中
- InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
- try {
- contextConfig.load(fis);
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (null != fis) {
- try {
- fis.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- public class Handler {
- private Pattern pattern; //正则
- private Method method;
- private Object controller;
- private Class<?>[] paramTypes;
- // 形参列表
- // 参数的名字作为key,参数的顺序,位置作为值
- private Map<String, Integer> paramIndexMapping;
- public Handler(Pattern pattern, Object controller, Method method) {
- this.pattern = pattern;
- this.method = method;
- this.controller = controller;
- paramTypes = method.getParameterTypes();
- paramIndexMapping = new HashMap<String, Integer>();
- putParamIndexMapping(method);
- }
- /**
- * 提取方法中加了注解的参数并且保存
- */
- private void putParamIndexMapping(Method method) {
- // 取得方法中参数的注解,得到的是一个二维数组
- // 一个方法有多个参数,一个参数可以有多个注解
- Annotation[][] pa = method.getParameterAnnotations();
- for (int i = 0; i < pa.length; i++) {
- for (Annotation annotation : pa[i]) {
- if (annotation instanceof RequestParam) {
- String paramName = ((RequestParam) annotation).value();
- if (!"".equals(paramName.trim())) {
- paramIndexMapping.put(paramName, i);
- }
- }
- }
- }
- // 提取方法中的request和response参数
- Class<?>[] paramsTypes = method.getParameterTypes();
- for (int i = 0; i < paramsTypes.length; i++) {
- Class<?> type = paramsTypes[i];
- if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
- paramIndexMapping.put(type.getName(), i);
- }
- }
- }
- public Pattern getPattern() { return pattern; }
- public Method getMethod() { return method; }
- public Object getController() { return controller; }
- public Class<?>[] getParamTypes() { return paramTypes; }
- }
- private String toLowerFirstCase(String simpleName) {
- char[] chars = simpleName.toCharArray();
- chars[0] += 32;
- return String.valueOf(chars);
- }
- }
|