当前位置: 首页 > news >正文

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

目录

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

1. Servlet的getInitParameter

Servlet有两个getInitParameter

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

web.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

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 {@Overridepublic 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

package com.hh.javaWebTest.service;public interface FruitService {
}

FruitServiceImpl.java

package com.hh.javaWebTest.service.impl;import com.hh.javaWebTest.service.FruitService;public class FruitServiceImpl implements FruitService {
}

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

package com.hh.javaWebTest.controller;import com.hh.javaWebTest.service.FruitService;
......省略部分......public class FruitController {private FruitService fruitService = null;......省略部分......}

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

<?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

package com.hh.javaWebTest.ioc;public interface BeanFactory {Object getBean(String id);
}

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

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);// 获取到主节点的beanObject 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();}}@Overridepublic Object getBean(String id) {return beanMap.get(id);}
}

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

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;@Overridepublic void init() throws ServletException {// 手动进行ViewBaseServlet的初始化super.init();beanFactory = new ClassPathXmlApplicationContext();}@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {......省略部分......// 获取fruit对应的classObject 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的属性中,实现了解耦
http://www.lryc.cn/news/513694.html

相关文章:

  • 免费开源跨平台SSH工具 WindTerm:媲美 xshell 的最佳平替(含详细使用教程)
  • 洛谷 P1075 [NOIP2012 普及组] 质因数分解 C语言
  • Apache Hive常见问题
  • 活动报名系统源码:JAVA同城服务系统活动报名同城圈子商家商城城市代理躲猫猫
  • 迈向Z级计算:Cloud4Science范式加速科学发现进程
  • ES IK分词字典热更新
  • Mac连接云服务器工具推荐
  • 从零开始:如何在 .NET Core 中优雅地读取和管理配置文件
  • JVM学习:CMS和G1收集器浅析
  • Science Robotics让软机器人“活”得更久的3D打印!
  • 模电面试——设计题及综合分析题0x01(含答案)
  • 二层交换机和三层交换机
  • 每天五分钟机器学习:凸集
  • Mongodb日志报错too many open files,导致mongod进程down
  • 关于 PCB线路板细节锣槽问题 的解决方法
  • 硬件基础知识笔记(2)——二级管、三极管、MOS管
  • 软件测试之非功能测试设计
  • GPU 英伟达GPU架构回顾
  • 机器学习 - 线性回归
  • NestJS 性能优化:从应用到部署的最佳实践
  • 本地快速推断的语言模型比较:Apple MLX、Llama.cpp与Hugging Face Candle Rust
  • 您的公司需要小型语言模型
  • 智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之14 方案再探 之5:知识树三类节点对应的三种网络形式及其网络主机
  • JR-RLAA系20路模拟音频多功能编码器
  • LabVIEW冷却风机性能测试系统
  • Python-Pdf转Markdown
  • pyQT + OpenCV相关练习
  • 音视频入门基础:MPEG2-PS专题(3)——MPEG2-PS格式简介
  • 云计算学习架构篇之HTTP协议、Nginx常用模块与Nginx服务实战
  • Zookeeper模式安装Kafka(含常规、容器两种安装方式)