Implement a simple Spring mvc framework through annotations

 

   1. First, let's build the architecture, just build an ordinary javaweb project and it's OK. The specific directory is as follows:

 

  

  For Xiaobai, you can take a closer look at the configuration of web.xml behind, and you can ignore the configuration of web.xml after a little research on javaweb.

      2. Start the code and run the entire project. Let's talk about ideas.

    

          (1).Controller annotation
     
copy code
package com.wuqi.annotation;
import java.lang.annotation.*;
/**
 * Created by wuqi on 2017/3/22.
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
    String value() default "";
}
copy code
     (2).Quatifier annotation
      
copy code
package com.wuqi.annotation;

import java.lang.annotation.*;

/**
 * Created by wuqi on 2017/3/25.
 */
@Target({ ElementType.FIELD }) // Annotation representing the annotation
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Quatifier {
    String value() default "";
}
copy code

 

      (3).RequestMapping annotation
     
copy code
package com.wuqi.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;
/**
 * Created by Shock on 2017/3/22.
 */
@Target({ ElementType.METHOD }) // Annotation on the method
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
    String value() default "";
}
copy code

 

          (4).Service annotation
     
copy code
package com.wuqi.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;
/**
 * Created by Shock on 2017/3/22.
 */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
    String value() default "";
}
copy code

 --------------------------------------------------------------------------------------------------------------------------

   

     (1).MyService interface
    
copy code
package com.wuqi.service.impl;

import java.util.Map;

/**
 * Created by wuqi on 2017/3/23.
 */
public interface MyService {

    int insert(Map map);

    int delete(Map map);

    int update(Map map);

    int select(Map map);

}
copy code

 

     (2).MyServiceImpl class
    
copy code
package com.wuqi.service.impl;
import com.wuqi.annotation.Service;

import java.util.Map;
/**
 * Created by wuqi on 2017/3/23.
 */
@Service("MyServiceImpl")
public class MyServiceImpl implements MyService {
    @Override
    public int insert(Map map) {
        System.out.println("MyServiceImpl:" + "insert");
        return 0;
    }

    @Override
    public int delete(Map map) {
        System.out.println("MyServiceImpl:" + "delete");
        return 0;
    }

    @Override
    public int update(Map map) {
        System.out.println("MyServiceImpl:" + "update");
        return 0;
    }

    @Override
    public int select(Map map) {
        System.out.println("MyServiceImpl:" + "select");
        return 0;
    }
}
copy code

 

      (3).SpringmvcService interface
    
copy code
package com.wuqi.service.impl;

import java.util.Map;

/**
 * Created by wuqi on 2017/3/23.
 */
public interface SpringmvcService {
    int insert(Map map);

    int delete(Map map);

    int update(Map map);

    int select(Map map);
}
copy code

 

   (4).MyServiceImpl class
    
copy code
package com.wuqi.service.impl;
import com.wuqi.annotation.Service;

import java.util.Map;
/**
 * Created by wuqi on 2017/3/23.
 */
@Service("SpringmvcServiceImpl")
public class SpringmvcServiceImpl implements SpringmvcService{
    @Override
    public int insert(Map map) {
        System.out.println("SpringmvcServiceImpl:" + "insert");
        return 0;
    }
    @Override
    public int delete(Map map) {
        System.out.println("SpringmvcServiceImpl:" + "delete");
        return 0;
    }
    @Override
    public int update(Map map) {
        System.out.println("SpringmvcServiceImpl:" + "update");
        return 0;
    }
    @Override
    public int select(Map map) {
        System.out.println("SpringmvcServiceImpl:" + "select");
        return 0;
    }

}
copy code

 --------------------------------------------------------------------------------------------------------------------------

   

  (1).SpringmvcController类
  
copy code
package com.wuqi.controller;
import com.wuqi.annotation.*;
import com.wuqi.service.impl.MyService;
import com.wuqi.service.impl.SpringmvcService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Created by wuqi on 2017/3/23.
 */
@Controller("wuqi")
public class SpringmvcController {
    @Quatifier("MyServiceImpl")
    MyService myService;
    @Quatifier("SpringmvcServiceImpl")
    SpringmvcService smService;

    @RequestMapping("insert")
    public String insert(HttpServletRequest request, HttpServletResponse response, String param) {
        myService.insert(null);
        smService.insert(null);
        return null;
    }

    @RequestMapping("delete")
    public String delete(HttpServletRequest request, HttpServletResponse response, String param) {
        myService.delete(null);
        smService.delete(null);
        return null;
    }

    @RequestMapping("update")
    public String update(HttpServletRequest request, HttpServletResponse response, String param) {
        myService.update(null);
        smService.update(null);
        return null;
    }

    @RequestMapping("select")
    public String select(HttpServletRequest request, HttpServletResponse response, String param) {
        myService.select(null);
        smService.select(null);
        return null;
    }
}
copy code

  --------------------------------------------------------------------------------------------------------------------------

  

      (1). The DispatcherServlet class inherits the javax.servlet.http.HttpServlet class
  
copy code
package com.wuqi.servlet;

import com.wuqi.annotation.*;
import com.wuqi.controller.SpringmvcController;
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.HashMap;
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;

/**
 * Created by Shock on 2017/3/23.
 */
public class DispatcherServlet extends HttpServlet{
    private static final long serialVersionUID = 1L;
    List<String> packageNames = new ArrayList<String>();
    // Instances of all classes, key is the value of the annotation, value is the instance of all classes
    Map<String, Object> instanceMap = new HashMap<String, Object>();
    Map<String, Object> handerMap = new HashMap<String, Object>();
    public DispatcherServlet() {
        super();
    }

    public void init(ServletConfig config) throws ServletException {
        // Package scan, get the files in the package
        scanPackage("com.wuqi");
        try {
            filterAndInstance();
        } catch (Exception e) {
            e.printStackTrace ();
        }
        // create a mapping relationship
        handerMap();
        // implement injection
        ioc();
    }

    private void filterAndInstance() throws Exception {
        if (packageNames.size() <= 0) {
            return;
        }
        for (String className : packageNames) {
            Class<?> cName = Class.forName(className.replace(".class", "").trim());
            if (cName.isAnnotationPresent(Controller.class)) {
                Object instance = cName.newInstance();
                Controller controller = (Controller) cName.getAnnotation(Controller.class);
                String key = controller.value();
                instanceMap.put(key, instance);
            } else if (cName.isAnnotationPresent(Service.class)) {
                Object instance = cName.newInstance();
                Service service = (Service) cName.getAnnotation(Service.class);
                String key = service.value();
                instanceMap.put(key, instance);
            } else {
                continue;
            }
        }
    }

    private void ioc() {

        if (instanceMap.isEmpty())
            return;
        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            // get all the properties inside
            Field fields[] = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);// Accessible private properties
                if (field.isAnnotationPresent(Quatifier.class));
                Quatifier quatifier = field.getAnnotation(Quatifier.class);
                String value = quatifier.value();
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(), instanceMap.get(value));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace ();
                } catch (IllegalAccessException e) {
                    e.printStackTrace ();
                }
            }
        }
        SpringmvcController wuqi = (SpringmvcController) instanceMap.get("wuqi");
        System.out.print(wuqi);
    }

    /**
     * Scan all files under the package
     *
     * @param Package
     */
    private void scanPackage(String Package) {
        URL url = this.getClass().getClassLoader().getResource("/" + replaceTo(Package));// Escape all the . to get the corresponding path
        String pathFile = url.getFile();
        File file = new File(pathFile);
        String fileList[] = file.list();
        for (String path : fileList) {
            File eachFile = new File(pathFile + path);
            if (eachFile.isDirectory()) {
                scanPackage(Package + "." + eachFile.getName());
            } else {
                packageNames.add(Package + "." + eachFile.getName());
            }
        }
    }

    /**
     * Create a mapping relationship
     */
    private void handerMap() {
        if (instanceMap.size() <= 0)
            return;
        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {
                Controller controller = (Controller) entry.getValue().getClass().getAnnotation(Controller.class);
                String ctvalue = controller.value();
                Method[] methods = entry.getValue().getClass().getMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping rm = (RequestMapping) method.getAnnotation(RequestMapping.class);
                        String rmvalue = rm.value();
                        handerMap.put("/" + ctvalue + "/" + rmvalue, method);
                    } else {
                        continue;
                    }
                }
            } else {
                continue;
            }

        }
    }

    private String replaceTo(String path) {
        return path.replaceAll("\\.", "/");
    }

    @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 {
        String url = req.getRequestURI();
        String context = req.getContextPath();
        String path = url.replace(context, "");
        Method method = (Method) handerMap.get(path);
        SpringmvcController controller = (SpringmvcController) instanceMap.get(path.split("/")[1]);
        try {
            method.invoke(controller, new Object[] { req, resp, null });
        } catch (IllegalAccessException e) {
            e.printStackTrace ();
        } catch (IllegalArgumentException e) {
            e.printStackTrace ();
        } catch (InvocationTargetException e) {
            e.printStackTrace ();
        }
    }
}
copy code

 

All the code has been posted, there is a web.xml

  
copy code
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
           version="3.1">
    <servlet>
        <servlet-name>testServlet</servlet-name>
        <servlet-class>com.wuqi.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <!-- ... -->
    <servlet-mapping>
        <servlet-name>testServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
copy code

 

  3. Well, the code has been posted. Now we need to talk about the idea. Because there is code, we use the code to describe the idea, which makes it easier to understand the meaning of the code. Then you can try to write according to your own level.

  •     First we need to scan all the files in the package (DispatcherServlet -> init(ServletConfig config) -> scanPackage("com.wuqi")), that is, the files with annotations. Then all files under the package are stored in the packageNames collection.
  •        At this time, we got all the files under the package, but we only need the part of the file that contains the annotations we specified, so we need to filter out the files we want, and in the process of filtering, we can filter out the class Direct instantiation and storage through Class.forName. Store it in the instanceMap collection, and set the corresponding key value for it. The key value is the value of the class annotation.
  •           Then traverse all the objects in the instanceMap collection, get the object of the specified annotation, and obtain all the methods of the object through reflection, traverse all the methods, and store the method of the specified annotation into the handerMap, and the key is the spliced ​​string ("/" + Object variable name + "/" + method name), value is the method (Method).
  •           Then we can traverse all objects in the instanceMap collection, obtain all property values ​​(fields) collections of the object through reflection, and then traverse the property value collection, assign the property value with the specified annotation, and assign the property value through the set method of Field. object is injected. (that is, injecting the Service object into the Controller)
  •          Finally, a method of an object can be called through the invoke method of reflection. (At this time, the object is stored in instanceMap, and the method is stored in handlerMap)

 

Reference link:

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325801597&siteId=291194637