Spring中的ApplicationContext所体现出来的工厂模式

news2025/8/3 15:40:51

Spring初体验

通常我们写代码时,先定义一个Class,然后再别的地方实例化,再进行调用,比如下边的Hello World的例子,类Hello有一个say()方法,用于打印出“Hello World”的字符串,另一个类App,承载程序的入口方法main(),我们在main()方法中实例化Hello类,并调用Hello.say()方法,代码如下:

Hello.java 

package demo;

public class Hello {
	public Hello() {
	}
	
	public void say() {
		System.out.println("Hello world!");
	}
}

 App.java

package demo;

public class App {

	public static void main(String[] args) {
//手动硬编码创建一个Hello对象
		Hello hello=new Hello();
		hello.say();	
		

	}

}

上边是入门的编程方式,在程序规模较小的情况是没啥问题的,但程序的规模成指数级增长后,可能成千上万的对象需要创建,可能很多对象的方法还是事务性,你如何在这成千上万个new出来的对象间进行事务处理?当然此处先点到为止,暂时还没进入这么高深的步骤。总之,Sun的工程师们为此发明了一个叫EJB的东西,将某些对象的创建进行统一管理,后来的Spring也继承了这一衣钵,EJB和Spring的差别就是,EBJ很臃肿并依赖程序运行的容器,而Spring则轻巧灵活,直接内嵌在程序中。总之就是不要自己去创建对象,统一由容器创建。

Spring定义了一个叫做ApplicationContext的接口,由其实现类完成对象的创建。按照Spring的思路,将上边的代码稍作转换后写法变成了这样:

package demo;

import org.springframework.context.support.StaticApplicationContext;

public class App {

	public static void main(String[] args) {

		//StaticApplicationContext是ApplicationContext的一个具体实现,用在独立运行的程序中
		StaticApplicationContext context = new StaticApplicationContext();
		context.registerBean(Hello.class);
		Hello hello = context.getBean(Hello.class);
		hello.say();

	}

}

这里我们看到多了一个StaticApplicationContext类的引用,实例化之后,对这Hello作了一些操作,然后通过这个context就可以获取Hello的实例,这里没有了new Hello()的代码,取而代之的是context.getBean(Class),后边的内容就跟前边一样了。这个例子暂时还没看到Spring有什么好处,但我们可以看到Spring的作用,就是用ApplicationContext接管了对象的实例化。当然,一般情况下我们也不会这样去使用Spring,并不会再实际项目中使用上下文获取对象,而是全权托管给Spring。

Spring用了反射机制创建对象,实际效果跟new一个对象是一样的。所以ApplicationContext在创建实例的时候也是调用构造方法的。为了演示Spring的托管效果,我们可以把say()方法在构造方法中调用,这样创建对象时就会调用say()方法,我们改一下Hello及App的代码:

Hello.java

package demo;

public class Hello {
	public Hello() {
		say();
	}
	
	public void say() {
		System.out.println("Hello world!");
	}
}

然后将main方法再改造一下,便只剩下Spring的内容,而无需编写自己的程序的调用代码,修改之后变成这样: 

App.java

package demo;

import org.springframework.context.support.StaticApplicationContext;

public class App {

	public static void main(String[] args) {

		
		StaticApplicationContext context = new StaticApplicationContext();
		context.registerBean(Hello.class);
//因为没有显式getBean()的调用,所以不会主动创建实例,我们用下边的语句进行预实例化。
		context.getBeanFactory().preInstantiateSingletons();
		

	}

}

运行App控制台打出“Hello World!”。

StaticApplicationContext就是所谓的上下文,我们将对象的生命周期交给这个上下文来管理。前边我只体验到了使用上下文来生成对象,实际上上下文还有更多的用法,可以提供除构造方法为的初始化以及销毁方法。由于StaticApplicationContext这个实现只用于测试,所以有些功能并未提供,为了体验更多的功能,接下来我们使用外部xml配置文件来指定要托管的类型。

ApplicationContext本身也有多种具体实现,使用不同的方式来进行自的初始化。ClassPathXmlApplicationContext就是其中之一,其目的是在classpath中搜索xml配置文件来进行上下的初始化。具体xml的配置文件怎么写可以参考下边的链接:Core Technologiesicon-default.png?t=M85Bhttps://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition

我们创建一个app.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--bean结点里可以用init-method属性指定被实例化对象的初始方法,类似前边的构造函数中调用。也可以用destroy-method属性指定对象销毁时调用的方法-->
	<bean class="demo.Hello" init-method="say" destroy-method="bye">
	</bean>
</beans>

Hello.java改成最初的样子:

package demo;

public class Hello {
	public Hello() {
	}
	
	public void say() {
		System.out.println("Hello world!");
	}

    public void bye() {
		System.out.println("Bye bye!");
	}
}

App.java改成如下:

package demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

	public static void main(String[] args) {

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
//关闭上下文时会销毁上下中创建的所有对象。
		context.close();

	}

}

运行App控制台打出“Hello World!”及“Bye bye!”。

工厂模式的应用

前文所体现出来的是设计模式中标准的工厂模式。每个上下文中都有一个beanFactory的实例,然后通过beanFactory产生出对象实例。意思就是说,就像工厂一样,你给定设计模型,工厂就照样子给你生产。

App.java中我们只实例化了一个上下文,但程序正常运行了。当然此处我们依然没有体验到Spring带来了什么好处,但可以看出,Spring的上下文就像一个容器,里边装载了我们需要的对象,本来我们需要在main()方法要写的代码,全部由Spring接管。同时不是说我们不需要处理对象的初始化,而是将对象的初始代码与逻辑代码进行分离,并且使用基于配置的方式实现,并不需要进行硬编码。

接下来,我们研究一下,在自己的程序之上,再套一层Spring究竟有什么好处,为什么要将对象初始化进行单独处理。

我们创建一个跟Hello类差不多的HelloTom类:

package demo;

public class HelloTom {

	public void say() {
		System.out.println("Hello Tome!");
	}
}

因为跟Hello长得一样,所以无论用不用Spring,调用方式都是一样的,我们先不用Spring来写个示例。为了使程序有一定扩展性,我们可以抽象出一个接口来,我们建一个SayHello的接口:

package demo;

public interface SayHello {
	void say();
}

然后Hello与HelloTom都实现这个接口:

画个UML类图看起来更直观一点

 

Hello.java

package demo;

public class Hello implements SayHello {

	public void say() {
		System.out.println("Hello world!");
	}
}

HelloTom.java

package demo;

public class HelloTom implements SayHello{

	public void say() {
		System.out.println("Hello Tom!");
	}
}

然后修改App.java第一次调用Hello.say():

package demo;

public class App {

	public static void main(String[] args) {
		SayHello hello=new Hello();
		hello.say();

	}

}

修改App.java再次调用HelloTom.say():

package demo;

public class App {

	public static void main(String[] args) {
		SayHello hello=new HelloTom();
		hello.say();

	}

}

从这两个示例中,可以看出两个不同的类型,却可以使用同一个接口类型来表示。不过,这个示例依然需要改两次代码才能实现不同的调用,能不能不改App.java就可以实现不同的调用呢?答案是可以的。我们可以使用工厂模式,通过运行参数告诉程序来选择哪个类型,但我们不必自己去写这样的逻辑,Spring已经自带了这个功能,可以直接拿用。这次我们还是用xml配置加载的方式,这样写的好处是不用在程序中硬编码,只要修改外部的xml文件后,重新运行程序就可以了。

先将App.java改成如下:

package demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

	public static void main(String[] args) {

		ApplicationContext context = new ClassPathXmlApplicationContext("app.xml");

		SayHello hello = context.getBean(SayHello.class);
		hello.say();

	}

}

然后修改app.xml后运行App.java:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean  class="demo.Hello" >	
	</bean>
</beans>

然后再修改app.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean  class="demo.HelloTom" >	
	</bean>
</beans>

 再次运行,发现两次结果是不同的,这个示例中我们除了刚开始设计需要改了下App.java,后边我们就不用再改了,而是修改明文的app.xml文件。这样做的好处就是,对于一个明确的功能,为了对环境做出一定的适应性,我们只要在外部调整一下配置文件,而不必要对项目的主体进行修改。实现了程序代码的轻耦合,也就是减少无关代码的之间的联系。这个示例中,任意一个实现SayHello接口的子类,都可以这样注册到Spring的上下文中,以达到不一样的效果。

当然,ApplicationContext并不仅仅是个工厂实现,它还给了我们统一的编程框架。无论是CS程序,还是WEB程序,我们写Spring都是类似乐高一样的组装方式。区别就在于使用什么样的上下文。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/34804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python和R绘制箱线图+抖动点

python和R绘制箱线图抖动点 散点箱线图 IPCC AR6 https://www.ipcc.ch/ 通过散点展示数据的直观分布 x轴刻度标签如果是“连续”数据&#xff0c;可添加渐变背景。通过渐变来体现升温幅度&#xff0c;美观形象。 python版本&#xff1a; 先手搓数据&#xff1a; import pan…

【构建ML驱动的应用程序】第 11 章 :监控和更新模型

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

c++11 unique_lock 使用

我们知道c11 提供了很多的类模板供我们使用&#xff0c;其中就有 lock_guard&#xff0c;这个用法也很简单&#xff0c;像这样&#xff1a; std::mutex m_mutex; std::lock_guard<std::mutex> guard(m_mutex); mutex 的 lock 和 unlock 完全是自动的&#xff0c;无需我…

新鲜出炉|基于深度学习的运维日志领域新进展

作者&#xff1a;云智慧算法工程师 Hugo Guo 运维日志领域研究方向主要包含异常日志检测、日志模式解析、日志内容分类、日志告警等。本篇文章介绍了热门异常检测模型 DeepLog、A2Log 等模型&#xff0c;以及云智慧自研模型 Translog 等。与此同时&#xff0c;在文章最后介绍了…

springboot自定义starter实践

创建一个spring项目 仿照spring的规范&#xff0c;artifact命名为xxx-spring-boot-starter 按需添加必要的依赖 这里只作为测试&#xff0c;就按最低的需求来只勾选如下三个 lombok、spring-boot-configuration-processor、spring-boot-autoconfigure 默认生成的项目结构如下…

使用HuggingFace实现 DiffEdit论文的掩码引导语义图像编辑

在本文中&#xff0c;我们将实现Meta AI和Sorbonne Universite的研究人员最近发表的一篇名为DIFFEDIT的论文。对于那些熟悉稳定扩散过程或者想了解DiffEdit是如何工作的人来说&#xff0c;这篇文章将对你有所帮助。 什么是DiffEdit? 简单地说&#xff0c;可以将DiffEdit方法…

【论文解读】Self-Explaining Structures Improve NLP Models

&#x1f365;关键词&#xff1a;性能提升、文本分类、信息推理 &#x1f365;发表期刊&#xff1a;arXiv 2020 &#x1f365;原始论文&#xff1a;https://arxiv.org/pdf/2012.01786.pdf &#x1f365;代码链接https://github.com/ShannonAI/Self_Explaining_Structures_Impro…

Java内部类

Java当中内部类主要有4种&#xff0c;分别是静态内部类、实例内部类/非静态内部类、局部内部类&#xff08;几乎不用&#xff09;、匿名内部类。静态内部类&#xff1a;被static修饰的内部成员类 ①在静态内部类只能访问外部类中的静态成员 ②创建静态内部类对象时&#xff0c;…

PB 2019 R3 MSOLEDBSQL SQL Server not available in Database Profiles

pb2019 pb2021,安装SQL OLEDB驱动时的注意事项&#xff1a; I installed PB 2019 R3, but when I go to the Database Profiles Window, MSOLEDBSQL SQL Server is not listed. Please go to the registry to check and see the key MSOLEDBSQL exists under HKEY_LOCAL_MACHI…

Python之tkinter图形界面设计学习二

图形用户界面&#xff08;简称GUI&#xff09;&#xff0c;是指采用图形方式显示的计算机操作用户界面。与计算机的命令行界面相比&#xff0c;图形界面对于用户的操作显得更加直观和简便。 一、tkinter模块 tkinter是Python的内置GUI模块。使用tkinter可以快速地创建GUI应用…

Vue脚手架Ⅲ(浏览器本地存储,Vue中的自定义事件,全局事件总线,消息订阅与发布(pubsub),nextTick,Vue封装的过度与动画)

文章目录脚手架3.10 浏览器本地存储3.11 Vue中的自定义事件3.12 全局事件总线3.13 消息订阅与发布&#xff08;pubsub&#xff09;3.14 nextTick3.15 Vue封装的过度与动画3.15.1 动画效果3.15.2 过度效果3.15.3 多个元素过度3.15.4 集成第三方动画3.15.5 总结过度和动画脚手架 …

达梦数据库安装与初始化超详细教程

陈老老老板&#x1f9b8;&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;国产数据库-达梦数据库&#xff08;主要讲一些达梦数据库相关的内容&#xff09;&#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下达梦数据库的下载与安装教程&#xff08;Windows版&…

一文解读 NFT 零版税

当我们听到“版税”这两个字时&#xff0c;脑海中首先浮现的是什么&#xff1f; 是对创作者作品权属的保护&#xff0c;还是项目方、平台额外的收益&#xff1f; 长期以来&#xff0c;版税作为一种收益机制&#xff0c;让买家“为知识和内容付费”&#xff0c;又让卖家“享受…

m在ISE平台下使用verilog开发基于FPGA的GMSK调制器

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 高斯最小频移键控&#xff08;Gaussian Filtered Minimum Shift Keying&#xff09;&#xff0c;这是GSM系统采用的调制方式。数字调制解调技术是数字蜂窝移动通信系统空中接口的重要组成…

决策树-相关作业

1. 请使用泰勒展开推导gini不纯度公式&#xff1b; 2. 请说明树的剪枝怎么实现&#xff1b; ●预剪枝&#xff08;pre-pruning&#xff09;通过替换决策树生成算法中的停止准则。&#xff08;例如&#xff0c;最大树深度或信息增益大于某一阈值&#xff09;来实现树的简化。预…

Flutter高仿微信-第39篇-单聊-删除单条信息

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; //删除对话框 Future<void> _showDeleteDialog(Ch…

要把项目问题管理好,项目经理需要这8个步骤!

项目问题时有发生&#xff0c;想让项目获得成功&#xff0c;项目经理需要有一个计划来快速有效地应对任何出现的问题。这是最佳实践问题管理过程的一部分&#xff0c;更是良好项目管理的核心本质。 项目问题的四种类型 任何事情都可能成为项目过程中影响项目计划的问题。项目…

ZYNQ之FPGA学习----FIFO IP核使用实验

1 FIFO IP核介绍 FIFO 的英文全称是 First In First Out&#xff0c; 即先进先出。与 FPGA 内部的 RAM 和 ROM 的区别是没有外部读写地址线&#xff0c; 采取顺序写入数据&#xff0c; 顺序读出数据的方式&#xff0c;使用起来简单方便&#xff0c;缺点就是不能像 RAM 和 ROM …

共创可持续出行未来 奔驰牵手《阿凡达:水之道》

11月20日&#xff0c;梅赛德斯-奔驰与20世纪影业及其出品电影《阿凡达&#xff1a;水之道》的品牌战略合作迈入崭新篇章&#xff01;电影《阿凡达&#xff1a;水之道》已定档于12月16日在全球多地公映&#xff0c;并于即日起开启主题为——“地球&#xff0c;我们的潘多拉”的联…

医疗设备远程监控 5G千兆工业网关智慧医疗

医疗设备远程监控 5G千兆工业网关智慧医疗 5G千兆工业网关的医疗设备远程监控应用&#xff0c;实现各医疗智能终端连接入网&#xff0c;医疗数据、监控视频、设备状态数据等&#xff0c;实时采集&#xff0c;边缘节点分析处理&#xff0c;低延时高速传输&#xff0c;工作人员远…