zoukankan      html  css  js  c++  java
  • 手写Spring框架学习笔记

    以下是咕泡公开课的学习笔记

    一、创建工程springdemo

    二、在pom中配置servlet

      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
          <version>2.5</version>
          <scope>provided</scope>
        </dependency>
    

    三、web.xml文件

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    
      <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>com.example.mvcframework.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>application.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
    

      

    四、资源文件

    application.properties文件

    scanPackage=com.example.demo

    五、创建注解

    1、Autowired 

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        String value() default  "";
    }
    

      

    2、Controller 

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Controller {
        String value() default  "";
    }
    

      

    3、RequestMapping 

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestMapping {
        String value() default  "";
    }
    

      

    4、RequestParam 

    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestParam {
        String value() default  "";
    }
    

      

    5、Service

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Service {
        String value() default  "";
    }
    

      

    六、创建DispatcherServlet

    public class DispatcherServlet extends HttpServlet {
    
        private Properties contextConfig = new Properties();
    
        private List<String> classNames = new ArrayList<>();
    
        private Map<String, Object> ioc = new HashMap<>();
    
        private Map<String,Method> handlerMapping = new HashMap<>();
    
        @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 {
            //运行阶段,根据用户请求的URL进行自动分发和调度
            try {
                doDispatch(req,resp);
            } catch (Exception e) {
                e.printStackTrace();
                resp.getWriter().write("500 Detail:" + Arrays.toString(e.getStackTrace()));
            }
        }
    
        private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
            if(this.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);
            //如何拿到实例?
            //唯一的方式从IOC容器中拿
            //继续投机取巧
            String beanName =  lowerFirstCase(method.getDeclaringClass().getSimpleName());
            System.out.println("beanName:" + beanName);
            Map<String,String[]> params = req.getParameterMap();
    
            method.invoke(ioc.get(beanName), new Object[]{req, resp,params.get("name")[0]});
    
    
           // System.out.println(method);
        }
    
    
        @Override
        public void init(ServletConfig config) throws ServletException {
            //1、加载配置文件
            doLoadConfig(config.getInitParameter("contextConfigLocation"));
    
            //2. 扫描所有相关的类
            doScanner(contextConfig.getProperty("scanPackage"));
    
            //3.初始化刚刚扫描到所有相关的类,并且把它保存在IOC容器中
            doInstance();
    
            //4. 实现依赖注入 DI 自动赋值
            doAutowired();
    
            //5. 初始化handlerMapping
            initHandleMapping();
    
            System.out.println("Spring is init");
        }
    
        private void initHandleMapping() {
            if(ioc.isEmpty()){
                return;
            }
    
            for(Map.Entry<String, Object> entry: ioc.entrySet()) {
                Class<?> clazz = entry.getValue().getClass();
                if(!clazz.isAnnotationPresent(Controller.class)){
                    continue;
                }
    
                String baseUrl = "";
                if(clazz.isAnnotationPresent(RequestMapping.class)){
                    RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                    baseUrl =  requestMapping.value();
                }
    
                Method[] methods = clazz.getMethods(); //只认public的方法
                for(Method method : methods){
                    if(!method.isAnnotationPresent(RequestMapping.class)){
                        continue;
                    }
                    RequestMapping requestMapping =  method.getAnnotation(RequestMapping.class);
                   String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
                    handlerMapping.put(url,method);
                    System.out.println("Mapped:" + url +"," + method);
                }
    
                Field[] fields = entry.getValue().getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (!field.isAnnotationPresent(Autowired.class)) {
                        continue;
                    }
                }
            }
        }
    
        private void doAutowired() {
            if(ioc.isEmpty()){
                return;
            }
    
            for(Map.Entry<String, Object> entry: ioc.entrySet()){
               Field[] fields = entry.getValue().getClass().getDeclaredFields();
               for(Field field: fields){
                   if(!field.isAnnotationPresent(Autowired.class)){
                       continue;
                   }
    
                  Autowired autowired =  field.getAnnotation(Autowired.class);
                  String beanName = autowired.value().trim();
                  if("".equals(beanName)){
                      beanName = field.getType().getName();
                  }
    
                  field.setAccessible(true); //强制暴力访问
                   try {
                       field.set(entry.getValue(), ioc.get(beanName));
                   } catch (IllegalAccessException e) {
                       e.printStackTrace();
                       continue;
                   }
    
               }
            }
        }
    
        private void doInstance() {
            if(classNames.isEmpty()){
                return;
            }
    
            try{
                for (String className: classNames) {
                   Class<?> clazz =  Class.forName(className);
                   //实例化,把实例化的对象保存到IOC容器之中
    
                    if(clazz.isAnnotationPresent(Controller.class)){
                        Object instance = clazz.newInstance();
                        String beanName = lowerFirstCase(clazz.getSimpleName());
                        ioc.put(beanName, instance);
                    } else if(clazz.isAnnotationPresent(Service.class)){
                        //因为Service有可能注入的不是它本身,有可能是它的实现类
                        //1、默认类名首字母小写
    
                        //2、自定义的beanName
                        Service service = clazz.getAnnotation(Service.class);
                        String beanName = service.value();
                        if("".equals(beanName)){
                             beanName = lowerFirstCase(clazz.getSimpleName());
                        }
                        Object instance = clazz.newInstance();
                        ioc.put(beanName, instance);
    
                        //3、如果是接口,投机取巧的方式,用它的接口类型作为key
                        Class<?>[] interfaces = clazz.getInterfaces();
                        for(Class<?> i : interfaces){
                            if(ioc.containsKey(i.getName())){
                                throw  new Exception("The beanName is exists");
                            }
                            ioc.put(i.getName(), instance);
                        }
    
                    }else{
                        continue;
                    }
    
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
        /**
         * 类名首字母小写
         */
        private String lowerFirstCase(String simpleName) {
            char[] chars = simpleName.toCharArray();
            chars[0] += 32;
            return  String.valueOf(chars);
        }
    
        private void doScanner(String scanPackage) {
            URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\.", "/"));
            File classDir = new File(url.getFile());
            for(File file : classDir.listFiles()){
                if(file.isDirectory()){
                    doScanner(scanPackage + "." + file.getName());
                }else{
                    if(file.getName().endsWith(".class")){
                        String classname = (scanPackage + "." +file.getName()).replace(".class","");
                        classNames.add(classname);
                    }
                }
            }
        }
    
        private void doLoadConfig(String contextConfigLocation) {
            InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
            try {
                contextConfig.load(is);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(is != null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

      

    七、使用

    1、创建接口

    public interface IDemoService {
        String get(String name);
    }
    

      

    2、创建服务

    @Service
    public class DemoService implements IDemoService {
        @Override
        public String get(String name) {
            return "hello," + name;
        }
    }
    

      

    3、创建Controller

    @Controller
    @RequestMapping("/demo")
    public class DemoAction {
    
        @Autowired
        private IDemoService demoService;
    
        @RequestMapping("/query")
        public  void query(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name){
            String result = demoService.get(name);
            try {
                resp.getWriter().write(result);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    
        @RequestMapping("/add")
        public  void add(HttpServletRequest req, HttpServletResponse resp,  @RequestParam("a")Integer a,  @RequestParam("b") Integer b){
            try {
                resp.getWriter().write(a + "+" + b + "=" + (a+b));
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    
        @RequestMapping("/remove")
        public  void remove(HttpServletRequest req, HttpServletResponse resp,  @RequestParam("id")Integer id){
    
        }
    }
    

      

    八、测试

    九、Spring十大优势

    1、面向接口编程
    2、IOC容器的问世
    3、AOP思想,使得程序员把大部分精力投入到业务
    4、Spring生态完善,Spring不仅仅只是一个框架
    5、兼容程度高。只要有Java的地方就有Spring的用武之地
    6、Spring的模块化拆分的非常精准,避免过度依赖(低耦合)
    7、轻量级,所有的操作都建立在JavaBean之上
    8、Spring与时俱进,全面支持Annotation,简化配置。如今的Spring可以实现配置裕兴
    9、内部工具类非常丰富,简化开发,提升开发效率
    10、Spring与各个开源框架可以实现无缝集成(Dubbo框架也是与Spring集成)
    核心:提升开发效

  • 相关阅读:
    HTML5新特性之离线缓存技术
    摘要
    典藏百度前端面试题
    idea连接mysql数据库
    报错:[stack Error: Can't find Python executable "python"] vue项目npm install
    SVN客户端(小乌龟)checkout(检出)文件(项目)到本地
    java日期Date工具类 日期格式转换
    radio标签 onchange事件
    js 写带有返回值的function遇到的返回值不正常的情况
    读取zip包内根目录文件的文件名
  • 原文地址:https://www.cnblogs.com/linlf03/p/9995135.html
Copyright © 2011-2022 走看看