JavaWeb Servlet的getInitParameter、业务层、控制反转IOC和依赖注入DI
目录
- 1. Servlet的getInitParameter
- 2. 业务层
- 3. 控制反转IOC和依赖注入DI
- 3.1 背景
- 3.2 实现如下
- 3.3 原理
1. Servlet的getInitParameter
Servlet有两个getInitParameter
- 一个是servletContext.getInitParameter,获取context-param的全局参数
- 一个是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数据传输对象,一般用于前后端分离)
区分业务对象和数据访问对象:
- DAO中的方法都是细粒度方法。一个方法只考虑一个操作,比如insert添加
- 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 原理
控制反转:
- 之前在FruitController中,我们创建Service属性, FruitService fruitService = new FruitServiceImpl()。fruitService的作用域(生命周期)是FruitController实例级别
- 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例。所有bean都存放在beanMap中,这个beanMap在一个BeanFactory中
- 因此,我们改变了之前的service实例等他们的作用域(生命周期)。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转
依赖注入:
- 之前在FruitController中,我们创建Service属性, FruitService fruitService = new FruitServiceImpl()。那么,FruitController和FruitService存在耦合
- 之后,我们将代码修改成FruitService fruitService = null;
- 然后,在配置文件中给FruitController这个bean定义了属性fruitService的值,解析配置文件,就可以将fruitService变量注入到FruitController的属性中,实现了解耦
相关文章:

JavaWeb Servlet的getInitParameter、业务层、控制反转IOC和依赖注入DI
目录 1. Servlet的getInitParameter2. 业务层3. 控制反转IOC和依赖注入DI3.1 背景3.2 实现如下3.3 原理 1. Servlet的getInitParameter Servlet有两个getInitParameter 一个是servletContext.getInitParameter,获取context-param的全局参数一个是servletConfig.ge…...

免费开源跨平台SSH工具 WindTerm:媲美 xshell 的最佳平替(含详细使用教程)
免费开源跨平台SSH工具 WindTerm WindTerm概述免费开源、免费开源、免费开源下载、安装WindTerm 屏幕截图WindTerm 主窗口 (zsh):WindTerm 拆分视图:WindTerm DigeWhite 主题: WindTerm 基本设置使用WindTerm连接到服务…...

洛谷 P1075 [NOIP2012 普及组] 质因数分解 C语言
题目: P1075 [NOIP2012 普及组] 质因数分解 - 洛谷 | 计算机科学教育新生态 题目描述 已知正整数 n 是两个不同的质数的乘积,试求出两者中较大的那个质数。 输入格式 输入一个正整数 n。 输出格式 输出一个正整数 p,即较大的那个质数。…...

Apache Hive常见问题
入门问题 什么是Apache Hive? 解释Hive的用途。Hive作为基于Hadoop的数据仓库工具是如何工作的?与传统关系型数据库相比,使用Hive有什么优势? Hive和关系型数据库管理系统(RDBMS)之间的区别是什么&#…...

活动报名系统源码:JAVA同城服务系统活动报名同城圈子商家商城城市代理躲猫猫
JAVA同城服务系统:打造多元化社交与娱乐新体验 在数字化时代,同城服务系统已成为连接城市生活的重要桥梁。我们精心打造的JAVA同城服务系统,不仅融合了活动报名、同城圈子、商家商城、城市代理等多重功能,还特别加入了创新的“躲…...

迈向Z级计算:Cloud4Science范式加速科学发现进程
传统超级计算机作为科学计算的核心支柱,在推动技术进步方面发挥了不可替代的作用,但随着科学智能时代下需求的多样化和复杂化,其扩展性和能效的局限逐渐显现。 针对这一挑战, 微软亚洲研究院 的研究员提出了 Cloud4Science 的新范…...

ES IK分词字典热更新
前言 在使用IK分词器的时候,发现官方默认的分词不满足我们的需求,那么有没有方法可以自定义字典呢? 官方提供了三种方式 一、ik本地文件读取方式 k插件本来已为用户提供自定义词典扩展功能,只要修改配给文件即可: …...

Mac连接云服务器工具推荐
文章目录 前言步骤1. 下载2. 安装3. 常用插件安装4. 连接ssh测试5. 连接sftp测试注意:ssh和sftp的区别注意:不同文件传输的区别解决SSL自动退出 前言 Royal TSX是什么: Royal TSX 是一款跨平台的远程桌面和连接管理工具,专为 mac…...

从零开始:如何在 .NET Core 中优雅地读取和管理配置文件
在.net中的配置文件系统支持丰富的配置源,包括文件(json、xml、ini等)、注册表、环境变量、命令行、Azure Key Vault等,还可以配置自定义配置源并跟踪配置的改变,然后按照优先级进行覆盖,总之对文件的配置有很多方法,这…...

JVM学习:CMS和G1收集器浅析
总框架 一、Java自动内存管理基础 1、运行时数据区 运行时数据区可分为线程隔离和线程共享两个维度,垃圾回收主要是针对堆内存进行回收 (1)线程隔离 程序计数器 虚拟机多线程是通过线程轮流切换、分配处理器执行时间来实现的。为了线程切换…...

Science Robotics让软机器人“活”得更久的3D打印!
软机器人硬件在医疗、探索无结构环境等领域有广泛应用,但其生命周期有限,导致资源浪费和可持续性差。软机器人结合软硬组件,复杂组装和拆卸流程使其难以维修和升级。因此,如何延长软机器人的生命周期并提高其可持续性成为亟待解决…...

模电面试——设计题及综合分析题0x01(含答案)
1、已知某温控系统的部分电路如下图(EDP070252),晶体管VT导通时,继电器J吸合,压缩机M运转制冷,VT截止时,J释放,M停止运转。 (1)电源刚接通时,晶体…...

二层交换机和三层交换机
一、交换机简述 交换机的主要功能包括物理编址、网络拓扑结构、错误校验、帧序列以及流控。交换机还具备了一些新的功能,如对VLAN(虚拟局域网)的支持、对链路汇聚的支持,甚至有的还具有防火墙的功能。 交换机除了能够连接同种类型…...

每天五分钟机器学习:凸集
本文重点 在SVM中,目标函数是一个凸函数,约束集合是一个凸集。因此,SVM问题可以转化为一个凸规划问题来求解。这使得SVM在实际应用中具有较高的计算效率和准确性。 凸集的定义 凸集是指一个集合中的任意两点之间的线段都完全包含在这个集合中。换句话说,给定集合C中的两…...

Mongodb日志报错too many open files,导致mongod进程down
【解决方案】 (1)进入到服务器,执行: ulimit -a 查看:open files这一行的数量,如果查询到的结果是1000左右,那多半是服务器限制。 (2)在当前session窗口执行如下&…...

关于 PCB线路板细节锣槽问题 的解决方法
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/144783817 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...

硬件基础知识笔记(2)——二级管、三极管、MOS管
Part 2 二级管、三极管、MOS管 1、二级管1.1肖特基二极管和硅二极管选型比较1.2到底是什么决定了二极管的最高工作频率?1.3二极管结电容和反向恢复时间都是怎么来的 1、二级管 1.1肖特基二极管和硅二极管选型比较 肖特基二极管的优势主要在速度和压降,对…...

软件测试之非功能测试设计
非功能测试设计 非功能:除了软件功能测试,其他都是非功能测试。 1.兼容 2.易用 3.性能(专项) 4.安全(专项) Web浏览器 兼容:Chrome浏览器、Edge浏览器、Firefox浏览器、Safari苹果浏览器 易用:参考竞品,主观感受为主 总结 1.非功能测试范围 兼容性、…...

GPU 英伟达GPU架构回顾
1999 年,英伟达发明了 GPU(graphics processing unit),本节将介绍英伟达 GPU 从 Fermi 到 Blackwell 共 9 代架构,时间跨度从 2010 年至 2024 年,具体包括费米(Feimi)、开普勒&#…...

机器学习 - 线性回归
线性回归模型的定义 线性回归(Linear Regression)的目标旨在找到可以描述目标值(输出变量)与一个或多个特征(输入变量)之间关系的一个线性方程或函数。 线性回归模型的表达式为 线性回归模型表达式的“齐次…...

NestJS 性能优化:从应用到部署的最佳实践
在上一篇文章中,我们介绍了 NestJS 的微服务架构实现。本文将深入探讨 NestJS 应用的性能优化策略,从应用层到部署层面提供全方位的优化指南。 应用层优化 1. 路由优化 // src/modules/users/users.controller.ts import { Controller, Get, UseInter…...

本地快速推断的语言模型比较:Apple MLX、Llama.cpp与Hugging Face Candle Rust
本地快速推断的语言模型比较:Apple MLX、Llama.cpp与Hugging Face Candle Rust 在自然语言处理(NLP)部署中,推断速度是一个关键因素,尤其是对于支持大型语言模型(LLM)的应用来说。随着Apple M1…...

您的公司需要小型语言模型
当专用模型超越通用模型时 “越大越好”——这个原则在人工智能领域根深蒂固。每个月都有更大的模型诞生,参数越来越多。各家公司甚至为此建设价值100亿美元的AI数据中心。但这是唯一的方向吗? 在NeurIPS 2024大会上,OpenAI联合创始人伊利亚…...

智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之14 方案再探 之5:知识树三类节点对应的三种网络形式及其网络主机
本文要点 前面讨论过(前面有错这里做了修正),三种簿册归档 对应通过不同的网络形式(分布式、对等式和去中心式)。每种网络主机上分别提供: 分布式控制脚本、 对等式账本 和 备记手本 通过以上讨论&#x…...

JR-RLAA系20路模拟音频多功能编码器
JR-RLAA系20路模拟音频多功能编码器 产品特色 (1)工业级19英寸标准设备,内置双电源 (2)内嵌Web Server,支持远程Web页面登陆后的统一配置操作 (3)支持20路音频输入 (4)支持Dolby Digital(AC-3) ,MPEG-2,AAC-LC/HE-AAC&#x…...

LabVIEW冷却风机性能测试系统
开发了基于LabVIEW软件及LabSQL工具包的冷却风机性能测试系统。系统通过高效的数据库访问技术,实现了对冷却风机测试过程中关键性能数据的采集、存储与管理,优化了测试流程并提升了数据处理的效率。 项目背景 在工业生产和科研测试中,准…...

Python-Pdf转Markdown
使用pdfminer.sixmarkdownify pdfminer.six可以提取Pdf文本内容markdownify可以将文本内容写markdown文件 安装 pip install pdfminer.six pip install markdownify实现 from pdfminer.high_level import extract_text from markdownify import markdownifydef pdf2markdo…...

pyQT + OpenCV相关练习
一、设计思路 1、思路分析与设计 本段代码是一个使用 PyQt6 和 OpenCV 创建的图像处理应用程序。其主要功能是通过一个图形界面让用户对图片进行基本的图像处理操作,如灰度化、翻转、旋转、亮度与对比度调整,以及一些滤镜效果(模糊、锐化、边…...

音视频入门基础:MPEG2-PS专题(3)——MPEG2-PS格式简介
一、引言 本文对MPEG2-PS格式进行简介。 进行简介之前,请各位先下载MPEG2-PS的官方文档。ITU-T和ISO/IEC都分别提供MPEG2-PS的官方文档。但是ITU提供的文档是免费的,ISO/IEC是付费的,所以我们主要阅读ITU提供的官方文档,比如较新…...

云计算学习架构篇之HTTP协议、Nginx常用模块与Nginx服务实战
一.HTTP协议讲解 1.1rsync服务重构 bash 部署服务端: 1.安装服务 [rootbackup ~]# yum -y install rsync 2.配置服务 [rootbackup ~]# vim /etc/rsyncd.conf uid rsync gid rsync port 873 fake super yes use chroot no max connections 200 timeout 600 ignore erro…...