JavaWeb Servlet的getInitParameter、业务层、控制反转IOC和依赖注入DI

目录

  • [1. Servlet的getInitParameter](#1. Servlet的getInitParameter)
  • [2. 业务层](#2. 业务层)
  • [3. 控制反转IOC和依赖注入DI](#3. 控制反转IOC和依赖注入DI)
    • [3.1 背景](#3.1 背景)
    • [3.2 实现如下](#3.2 实现如下)
    • [3.3 原理](#3.3 原理)

1. Servlet的getInitParameter

Servlet有两个getInitParameter

  1. 一个是servletContext.getInitParameter,获取context-param的全局参数
  2. 一个是servletConfig.getInitParameter,取init-param的servlet参数
    示例如下:

web.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <context-param>
        <param-name>global-name</param-name>
        <param-value>global-value</param-value>
    </context-param>

    <servlet>
        <servlet-name>Demo01Servlet</servlet-name>
        <servlet-class>com.hh.javaWebTest.demo.Demo01Servlet</servlet-class>
        <init-param>
            <param-name>servlet-name1</param-name>
            <param-value>servlet-value1</param-value>
        </init-param>
        <init-param>
            <param-name>servlet-name2</param-name>
            <param-value>servlet-value2</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Demo01Servlet</servlet-name>
        <url-pattern>/demo01</url-pattern>
    </servlet-mapping>

</web-app>

Demo01.java

Java 复制代码
package com.hh.javaWebTest.demo;


import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;

/*
// web.xml和注解选择一种
@WebServlet(
        urlPatterns = {"/demo01"} ,
        initParams = {
                @WebInitParam(name="servlet-name1",value="servlet-value1"),
                @WebInitParam(name="servlet-name2",value="servlet-value2")
        }
)
 */
public class Demo01Servlet extends HttpServlet {

    @Override
    public void init() throws ServletException {

        // 获取context-param的全局参数
        // request.getServletContext();
        // request.getSession().getServletContext();
        ServletContext servletContext = getServletContext();
        String globalValue = servletContext.getInitParameter("global-name");
        System.out.println("globalValue = " + globalValue);    // globalValue = global-value

        // 获取init-param的servlet参数
        ServletConfig servletConfig = getServletConfig();
        String servletValue1 = servletConfig.getInitParameter("servlet-name1");
        System.out.println("servletValue1 = " + servletValue1);    // servletValue1 = servlet-value1

    }
}

2. 业务层

Model1介绍:典型的就是JSP,用HTML(CSS、JS) + Java代码(将数据提供给页面的代码,加上和数据库通信的代码)。这样的Java代码显得很乱

Model2,即MVC: Model(模型) + View(视图) + Controller(控制器)

  • 视图层:用于做数据展示以及和用户交互的一个界面
  • 控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
  • 模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件(BO业务对象),有数据访问层组件(DAO数据访问对象)、有Service传输给Controller的组件(DTO数据传输对象,一般用于前后端分离)

区分业务对象和数据访问对象:

  1. DAO中的方法都是细粒度方法。一个方法只考虑一个操作,比如insert添加
  2. BO中的方法属于业务方法,粒度是比较粗的,对应复杂的业务逻辑处理,如注册新用户,需要调用很多DAO,和做很多逻辑操作

3. 控制反转IOC和依赖注入DI

3.1 背景

在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。但我们系统架构设计的一个原则是: 高内聚低耦合。即层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合。我们可以通过控制反转IOC和依赖注入DI来实现高内聚低耦合

3.2 实现如下

FruitService.java

Java 复制代码
package com.hh.javaWebTest.service;

public interface FruitService {
}

FruitServiceImpl.java

Java 复制代码
package com.hh.javaWebTest.service.impl;

import com.hh.javaWebTest.service.FruitService;

public class FruitServiceImpl implements FruitService {
}

FruitController.java。里面有一个FruitService类型的属性

Java 复制代码
package com.hh.javaWebTest.controller;

import com.hh.javaWebTest.service.FruitService;
......省略部分......

public class FruitController {

    private FruitService fruitService = null;

......省略部分......

}

applicationContext.xml。定义了两个bean,同时定义了fruitService是FruitController的属性

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>

<beans>
    <bean id="fruitService" class="com.hh.javaWebTest.service.impl.FruitServiceImpl"/>

    <!--
    Node节点:
        Element元素节点
        Text文本节点
    -->
    <!-- 子节点总共有5个。空白Text、注释Text、空白Text、property元素节点、空白Text-->
    <bean id="fruit" class="com.hh.javaWebTest.controller.FruitController">
        <!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值 -->
        <property name="fruitService" ref="fruitService"/>
    </bean>
</beans>

BeanFactory.java

Java 复制代码
package com.hh.javaWebTest.ioc;

public interface BeanFactory {
    Object getBean(String id);
}

ClassPathXmlApplicationContext.java。解析applicationContext.xml,将bean放到beanMap中,然后给各个bean设置property属性

Java 复制代码
package com.hh.javaWebTest.ioc;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class ClassPathXmlApplicationContext implements BeanFactory {

    private Map<String, Object> beanMap = new HashMap<>();

    public ClassPathXmlApplicationContext() {
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(inputStream);

            NodeList beanNodeList = document.getElementsByTagName("bean");
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class controllerBeanClass = Class.forName(className);
                    Object beanObj = controllerBeanClass.getDeclaredConstructor().newInstance();

                    beanMap.put(beanId, beanObj);
                }
            }

            // 组装bean之间的依赖关系
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    // 获取子节点
                    NodeList beanChildNodeList = beanElement.getChildNodes();
                    for (int j = 0; j < beanChildNodeList.getLength(); j++) {
                        Node beanChildNode = beanChildNodeList.item(j);
                        // 从子节点找到property节点
                        if (beanChildNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())) {
                            Element propertyElement = (Element) beanChildNode;
                            String propertyName = propertyElement.getAttribute("name");
                            String propertyRef = propertyElement.getAttribute("ref");
                            // 获取属性的值
                            Object refObj = beanMap.get(propertyRef);
                            // 获取到主节点的bean
                            Object beanObj = beanMap.get(beanId);
                            Class beanClazz = beanObj.getClass();
                            // 获取到主节点的bean的属性
                            Field propertyField = beanClazz.getDeclaredField(propertyName);
                            propertyField.setAccessible(true);
                            // 设置属性的值
                            propertyField.set(beanObj, refObj);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }
}

DispatcherServlet.java。不在DispatcherServlet进行applicationContext.xml的解析,而是直接从BeanFactory获取bean

Java 复制代码
package com.hh.javaWebTest.servlet;

import com.hh.javaWebTest.ioc.BeanFactory;
import com.hh.javaWebTest.ioc.ClassPathXmlApplicationContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
......省略部分......

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {


    private BeanFactory beanFactory;

    @Override
    public void init() throws ServletException {
        // 手动进行ViewBaseServlet的初始化
        super.init();

        beanFactory = new ClassPathXmlApplicationContext();
    }


    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

......省略部分......

        // 获取fruit对应的class
        Object controllerBeanObj = beanFactory.getBean(servletPath);

......省略部分......
    }
}

3.3 原理

控制反转:

  1. 之前在FruitController中,我们创建Service属性, FruitService fruitService = new FruitServiceImpl()。fruitService的作用域(生命周期)是FruitController实例级别
  2. 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例。所有bean都存放在beanMap中,这个beanMap在一个BeanFactory中
  3. 因此,我们改变了之前的service实例等他们的作用域(生命周期)。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转

依赖注入:

  1. 之前在FruitController中,我们创建Service属性, FruitService fruitService = new FruitServiceImpl()。那么,FruitController和FruitService存在耦合
  2. 之后,我们将代码修改成FruitService fruitService = null;
  3. 然后,在配置文件中给FruitController这个bean定义了属性fruitService的值,解析配置文件,就可以将fruitService变量注入到FruitController的属性中,实现了解耦
相关推荐
码农幻想梦2 天前
实验十 Servlet(一)
hive·hadoop·servlet
智客工坊4 天前
AI编程助手带来的洞察和启发——程序员职业的变革
java·javaweb·管理
未来并未来6 天前
通过反射搭建简易的Servlet层自动化映射参数并调用Service层业务方法的框架
运维·servlet·自动化
UVCuttt6 天前
三天急速通关JavaWeb基础知识:Day 1 后端基础知识
java·servlet·java-ee·tomcat
简 洁 冬冬7 天前
Java中的Servlet
java·开发语言·servlet
阳光阿盖尔8 天前
【javaweb项目idea版】蛋糕商城(可复用成其他商城项目)
java·servlet·intellij-idea·javaweb·商城·蛋糕商城·购物商城
Suwg20911 天前
【由浅入深认识Maven】第4部分 maven在持续集成中的应用
servlet·ci/cd·maven
花月C11 天前
Java Web-Tomcat Servlet
java·前端·servlet·java-ee·tomcat
怀旧66613 天前
Servlet 详解
java·开发语言·servlet·个人开发
jcsx13 天前
证券量化交易选择合适的编程语言
javascript·servlet·numpy·pandas·pyqt