学习笔记(Spring底层+Spring与Servlet整合)

传统的Servlet开发方式的不足

  • 同一个类型的业务要进行多个Servlet的编写
    将业务申请放在一个servlet中(DispatcherServlet)接收所有请求,最后进行分发。
  • 对象管理不方便
  1. 将对象的创建和属性的注入存放在xml文件中,对xml文件中的bean和类进行匹配,放入Map中。
  2. 对需要创建的类上添加上注解,然后通过注解对属性进行匹配放入Map中

Code(列举几个主要类)

DispatcherServlet.java

  • 接收输入的url,并将对应的url存放在map中
public class DispatcherServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("有请求进来了 ");
        Map applicationContext = (Map)getServletContext().getAttribute("applicationContext");  //存放类名和对应的对象
        Map handlerMapping = (Map)getServletContext().getAttribute("handlerMapping");   //存放url下所有的方法

        String requestURI = req.getRequestURI();
        String[] split = requestURI.split("/");
        String baseUrl = "/" + split[1];
        String actionUrl = "/" + split[2];
        String url = baseUrl + actionUrl;
        Method method = (Method)handlerMapping.get(url);  //  /goods/add,根据url找到方法
        try {
            method.setAccessible(true);
            //调用具体的处理请求的方法
            method.invoke(applicationContext.get(split[1] + "Controller"),req,resp);   //创建对象执行方法
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

ContextLoadListener

  • 在初始化方法中扫描注解并进行对应操作
public class ContextLoadListener implements ServletContextListener {

    public List<String> allClassNameList = new ArrayList<>();
    public Map<String,Object> beanFactory = new HashMap<>();
    public Map<String, Method> handerMapping =  new LinkedHashMap<>();
    /**
     *
     * Tomcat启动时执行
     * 在tomcat启动时加载(初始化)容器,创建容器中的对象
     * @param sce
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //1.扫描包(由使用者来配置)
        //读入需要扫描的包名
        Properties properties = new Properties();
        try {
            properties.load(DispatcherServlet.class.getClassLoader().getResourceAsStream("application.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String basePackageName = properties.getProperty("scan-package");

        //把包名转成classPath的路径
        String basePackagePath = basePackageName.replaceAll("\\.", "/");
        //扫描指定包下面的所有的类
        doScan(basePackagePath);

        System.out.println(allClassNameList);

        //2.判断扫描出来的所有的类哪些增加了 @Compoent @Controller @Service @Repostory 把这些添加了注解的类创建对象,加入到bean工厂中

        for (String className : allClassNameList) {
            Class<?> aClass = null;
            try {
                aClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            if(aClass.isAnnotationPresent(Component.class)){
                String beanName = aClass.getAnnotation(Component.class).value();

                if("".equals(beanName)){
                    char[] simpleNameArray = aClass.getSimpleName().toCharArray();
                    simpleNameArray[0] += 32;
                    beanName = aClass.getSimpleName();
                }
                try {
                    beanFactory.put(beanName,aClass.newInstance());
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            if(aClass.isAnnotationPresent(Service.class)){
                String beanName = aClass.getAnnotation(Service.class).value();

                if("".equals(beanName)){
                    char[] simpleNameArray = aClass.getSimpleName().toCharArray();
                    simpleNameArray[0] += 32;
                    beanName = aClass.getSimpleName();
                }
                try {
                    beanFactory.put(beanName,aClass.newInstance());
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            if(aClass.isAnnotationPresent(Controller.class)){
                String beanName = aClass.getAnnotation(Controller.class).value();

                if("".equals(beanName)){
                    char[] simpleNameArray = aClass.getSimpleName().toCharArray();
                    simpleNameArray[0] += 32;
                    beanName = aClass.getSimpleName();
                }
                try {
                    beanFactory.put(beanName,aClass.newInstance());
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            if(aClass.isAnnotationPresent(Repository.class)){
                String beanName = aClass.getAnnotation(Repository.class).value();

                Object obj = Proxy.newProxyInstance(ContextLoadListener.class.getClassLoader(), new Class[]{aClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


                        if(method.isAnnotationPresent(Query.class)){
                            //查询操作
                            String sql = method.getAnnotation(Query.class).value();
                            List<Map<String, Object>> mapList = JdbcUtils.getQueryRunner().query(sql, new MapListHandler());
                            return mapList;
                        }
                        if(method.isAnnotationPresent(Update.class)){
                            //增删改操作
                            String sql = method.getAnnotation(Update.class).value();
                            int update = JdbcUtils.getQueryRunner().update(sql,args);
                            return update;
                        }


                        return null;
                    }
                });
                if("".equals(beanName)){
                    char[] simpleNameArray = aClass.getSimpleName().toCharArray();
                    simpleNameArray[0] += 32;
                    beanName = aClass.getSimpleName();
                }
                beanFactory.put(beanName,obj);
            }
        }

        //3.依赖注入
        beanFactory.forEach((beanName,obj) -> {
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true); //强问

                //普通的String的value值
                if(declaredField.isAnnotationPresent(StringValue.class)){
                    try {
                        declaredField.set(obj,declaredField.getAnnotation(StringValue.class).value());
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                }


                //注入的是对象
                if(declaredField.isAnnotationPresent(Qualifier.class)){
                    String bName = declaredField.getAnnotation(Qualifier.class).value();
                    Object o = beanFactory.get(bName);
                    try {
                        declaredField.set(obj,o);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }


                }

            }
        });

        //4.测试
        MemberController memberController = (MemberController) beanFactory.get("memberController");
        memberController.add();

        //5.解析包含@Controller注解的类的方法,看哪些方法上有@RequestMapping

        beanFactory.forEach((beanName,obj)->{
            if(obj.getClass().isAnnotationPresent(Controller.class)){
                String baseUrl = "";
                //解析Controller上面有无@RequestMapping
                if(obj.getClass().isAnnotationPresent(RequestMapping.class)){
                    baseUrl = obj.getClass().getAnnotation(RequestMapping.class).value();
                }

                Method[] declaredMethods = obj.getClass().getDeclaredMethods();
                for (Method declaredMethod : declaredMethods) {
                    if (declaredMethod.isAnnotationPresent(RequestMapping.class)) {
                        String url = declaredMethod.getAnnotation(RequestMapping.class).value();

                        String allUrl = (baseUrl + url).trim().replaceAll("// ","/");

                        System.out.println(allUrl);

                        handerMapping.put(allUrl,declaredMethod);
                    }
                }
            }
        });
        sce.getServletContext().setAttribute("applicationContext",beanFactory);
        sce.getServletContext().setAttribute("handlerMapping",handerMapping);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }

    public void doScan(String basePackagePath){
        //获取classPath路径在硬盘中的url
        URL url = DispatcherServlet.class.getClassLoader().getResource(basePackagePath);

        //从url中获取文件对象(绝对路径)
        File basePackageFile = new File(url.getFile());
        for(File file : basePackageFile.listFiles()){
            if(file.isDirectory()){
                doScan(basePackagePath + "/" + file.getName()); //递归
            }else{
                allClassNameList.add(basePackagePath.replaceAll("/","\\.") + "." + file.getName().replaceAll(".class",""));
            }
        }

    }
}

Spring与Servlet的整合

.pom文件
导入Spring和Servlet依赖

      <!--只需要引入这一个依赖即可,因为这个依赖包含  beans  core  context   web ..-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.2.1.RELEASE</version>
      </dependency>

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

web.xml
配置Spring的配置文件和监听器

    <!--Spring的配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application.xml</param-value>
    </context-param>


    <!--    监听tomcat的启动,在启动时初始化容器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

application.xml
配置组件扫描器

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置注解扫描器-->
    <context:component-scan base-package="com.lyx.spring"/>
</beans>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值