从一个简单的例子看spring ApplicationContext上下文隔离
前言
某天,浏览博客园的时候,对首页上面的一篇文章,标题为:<<一个普通类就能干趴你的springboot,你信吗?>>,文章链接:https://www.cnblogs.com/rongdi/p/11780204.html 很是感兴趣。点进去之后,大致看一下。该篇博文主要说的是在使用spring boot环境下想创建一个名为Environment的bean,结果发现创建不了,于是不断调试终于找到了“真理”。
说真的。这篇博文的内容非常长,主要也是记录调试过程的“流水账”。我也只看到了看头,就迅速拉到文章结尾看一下。比较让我感到震惊的是,博主提到为了写这篇文章花费了很长的时间,从该博主的这篇文章中摘录了一句话:周五晚上从下班回家一边一步步断点一遍写这篇博客。可以看出该博主很是用心,调试程序是一件很费心,耗时的事。于是评论区送上一个大大的赞。
无论是调试还是阅读Spring源码,真的是一件很枯燥的事,非常考验人的耐心,由其是spring发展了这么多年,已经形成了生态圈。其代码也是高度抽象。曾经对spring进行过一番折腾,也是为了给自己所在小团队提供一个基于spring封装的迷你型的小框架。
由于有折腾过spring的经历,我一眼就看出了问题的所在。根本原因就在于spring框架自身也有一个Environment类,在应用程序启动时也会向spring ApplicationContext中注入名为environment的bean,这样就会跟博主命名Environment类注入名为environment的bean产生冲突,因为这两个bean的名称一样。
像BAT这样级别的公司往往内部或多或少都会有自己的框架,这些框架往往都是由一个类似于基础架构部的团队来负责提供的,这样应用开发小组会基于这个框架快速的开发应用。应用开发者一般只会关心如何使用框架,一般都由专门的人来折腾框架。虽然我没有在这样体量的公司里面工作过,鉴于之前折腾框架经验来看。框架无论多么的高大上,有一点是可以肯定的时,框架所使用的资源跟应用所使用的资源肯定会进行隔离。
为什么会这样说呢,打个比方。封装框架的过程中肯定会引入一些第三方的jar,应用在开发的过程也会引用第三方jar,假设框架和应用同时引用一个jar但是二者的版本不同?那可能会导致程序在运行的过程中搞不好就会出现 java.lang.NoSuchMethodException异常,包冲突了。这时该怎么办?如果要框架jar跟应用的jar保持一致,那就不得了,这么多应用都使用框架进行开发,牵一发而动全身,风险即大。如果应用使用跟框架一样的jar,但是这个jar又没有相应的方法,使用不了。可以想象一样,如果框架和应用没有分别定义自身的类加载器来加载各自的所引用的jar,遇到这样的场景,解决起来将会非常棘手。
所以在封装框架的过程中,都会对框架所引用的资源跟应用所使用的资源都要进行相应的隔离,如果不隔离的话,框架三天两天就要改动,对应用开发者来说就会认为框架非常的不稳定。由其在BAT这样大体量的公司,开发人员如此众多,对框架提供技术支撑的人不会很多,框架如果不够稳定的话,搞不好那么那些提供技术支撑人员的电话,每天都会响个不停,会到处去解决问题,疲于奔命。就像那篇文章提到定义Envrionment bean时候,应用就会跑起不来,打电话给技术支撑的人,人家一过来捣鼓一番对像你说,老兄,对不住啊,命名冲突了,换这个名字吧。也许重新命个名字了事,但是有些场景这个类的名字改不了,别人的代码已经固定了要使用这个名字来调用你的bean,改名字别人就调不了。重新命名也许可以解决问题,但内心深处,你会对这个框架失去信心了。什么框架,还限制别人bean的名字。
像spring框架就提供了对ApplicationContext进行隔离的功能,可以轻松解决这个问题。在spring官网的文档中我也没有看到有提到,不允许应用程序注入一个命名为Environment的Bean。
程序出错
我已经将复现同样错误的示例程序代码上传到了gitee上面。大家可以把代码拉下来,跑起来会出现跟那篇文章中提所到的一模一样错误。 出现这样错误的原因就是由于两个同名的类注入到同一个ApplicationContext中导致的。
示例代码链接:https://gitee.com/fiercetiger/laboratory/tree/master/applicationcontext-test
导致程序出错,Bean的源码如下所示:
@Component
public class Environment {
}
ApplicationContext隔离
spring ApplicationContext是可以设置成上下级关系的,查找bean的时候如果在当前的ApplicationContext中没有找到的话,就会到自己的父级的ApplicationContext中去查找,一直向上回溯,如果找到就会返回。这样一来的话,我们可以这样处理。让应用的ApplicationContext作为spring框架的ApplicationContext的父级。示例程序,我也提交到了gitee上面,可以把代码拉下来,跑一下就会发现没有报错。
示例代码链接:https://gitee.com/fiercetiger/laboratory/tree/master/applicationcontext-test2

关键代码如下所示,定义一个类继承spring boot的SpringApplication类,覆盖其createApplicationContext方法,在方法中首先创建应用的ApplicationContext,并注入应用所定义的Environment Bean,随后将其设置为spring boot ApplicationContext的父级。为了更好的演示向上回溯查找Bean的效果,特意定义了一个MyService Bean,这个Bean注入到spring boot ApplicationContext中,并且在MyService Bean中自动注入对应用所定义的Environment Bean的依赖。当应用程序启动之后,没有报错。说明了MyService Bean成功注入了父级的application context中所定义的Environment Bean
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.StaticApplicationContext; public class MySpringApplication extends SpringApplication { public MySpringApplication(Class<?>[] classes){
super(classes);
} @Override
protected ConfigurableApplicationContext createApplicationContext(){ StaticApplicationContext parent=new StaticApplicationContext();
parent.registerBean(Environment.class);
parent.refresh(); ConfigurableApplicationContext child=super.createApplicationContext();
child.setParent(parent); return child;
}
}
结尾
写这篇文章的旨在分享有关spring ApplicationContext 一个小小的知识点,Spring所涉及到的知识点非常庞杂。那篇文章的博主为了弄清楚问题的真相,花费大量的程序来调试程序,还花了大篇幅的文章记录下来,可以看到出该博主是一个对技术有着执着追求的人。这篇文章也完整呈现了我在那篇文章评论区中所提到,可以采用对applicationcontext进行分层来解决这一问题。
从一个简单的例子看spring ApplicationContext上下文隔离的更多相关文章
- Spring-Context之一:一个简单的例子
很久之前就想系统的学习和掌握Spring框架,但是拖了很久都没有行动.现在趁着在外出差杂事不多,就花时间来由浅入深的研究下Spring框架.Spring框架这几年来已经发展成为一个巨无霸产品.从最初的 ...
- 一个简单的例子搞懂ES6之Promise
ES5中实现异步的常见方式不外乎以下几种: 1. 回调函数 2. 事件驱动 2. 自定义事件(根本上原理同事件驱动相同) 而ES6中的Promise的出现就使得异步变得非常简单.promise中的异步 ...
- 一个简单的例子了解states
在大规模的配置管理工作中,我们要编写大量的states.sls文件.top.sls是states系统的入口文件,它负责指定哪些设备调用哪些states.sls文件.statse的默认工作目录是在/sr ...
- 跨站脚本功攻击,xss,一个简单的例子让你知道什么是xss攻击
跨站脚本功攻击,xss,一个简单的例子让你知道什么是xss攻击 一.总结 一句话总结:比如用户留言功能,用户留言中写的是网页可执行代码,例如js代码,然后这段代码在可看到这段留言的不同一户的显示上就会 ...
- Linux内核中的信号机制--一个简单的例子【转】
本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...
- 从一个简单的例子谈谈package与import机制
转,原文:http://annie09.iteye.com/blog/469997 http://blog.csdn.net/gdsy/article/details/398072 这两篇我也不知道到 ...
- 用一个简单的例子来理解python高阶函数
============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...
- 关于apriori算法的一个简单的例子
apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...
- 扩展Python模块系列(二)----一个简单的例子
本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...
随机推荐
- 2017CCSP-01 五子棋 简单模拟
题面和数据 对于每个空格,先定义一个变量cnt=0,表示空格填充后对五子数量的变化,四个方向进行两边搜索,设对于每个方向连续的白棋子分别为\(wa\),\(wb\),有以下几种情况. \(wa> ...
- .Net Core 商城微服务项目系列(三):Ocelot网关接入Grafana监控
使用网关之后我们面临的一个问题就是监控,我们需要知道网关的实时状态,比如当前的请求吞吐量.请求耗费的时间.请求峰值甚至需要知道具体哪个服务的哪个方法花费了多少时间.网关作为请求的中转点是监控品牌的要塞 ...
- Java基础学习笔记(四) - 认识final关键字、权限修饰符和内部类
一.final关键字 为什么要使用 final 关键字? 通过继承我们知道,子类可以重写父类的成员变量和方法.final 关键字可以用于修饰父类,父类成员变量和方法,使其内容不可以被更改. 1.被修饰 ...
- 小白学 Python(1):开篇
人生苦短,我用 Python 引言 大家好,可能大家都对我比较熟悉了,不熟悉请去面壁(现在熟悉一下也来得及)~ 简单做一个自我介绍,我是极客挖掘机的唯一作者,一位油腻的 Java 程序员[臭鸡蛋什么的 ...
- System NT Kernel & System占用CPU 12%左右 终极解决方案,原来是更新惹的祸
任务管理器发现 system进程持续占用12%左右的cpu,网上搜索到的很多方法均无效 误打误撞发现了这个方法,亲测可用 卸载系统补丁(KB41000347),提升10%的cpu性能 卸载补丁前: ...
- Unreal Engine 4 系列教程 Part 1:入门
原文:Unreal Engine 4 Tutorial for Beginners: Getting Started 作者:Tommy Tran 译者:Shuchang Liu 本篇教程将引导你安装U ...
- Spring Boot WebFlux 集成 Mongodb 数据源操作
WebFlux 整合 Mongodb 前言 上一讲用 Map 数据结构内存式存储了数据.这样数据就不会持久化,本文我们用 MongoDB 来实现 WebFlux 对数据源的操作. 什么是 MongoD ...
- Vue-CLI项目-vue-cookie与vue-cookies处理cookie
08.31自我总结 Vue-CLI项目-vue-cookie与vue-cookies处理cookie vue-cookie 一.模块的安装 npm install vue-cookie --save ...
- mac专业视频剪辑软件 Final Cut Pro 10.4.6破解版
Final Cut Pro简称FCP,它是 Mac平台上最好的视频剪辑软件,可用来视频剪辑.后期特效等.可编辑从标清到4K的各种分辨率视频,ColorSync管理的色彩流水线则可保证全片色彩的一致性. ...
- 后台模板引擎ejs与前台模板引擎artTemplate的简单介绍
动态网页是指前端页面当中的数据内容来源于后台数据库,前端的html代码会随着后台数据的变化而变化,是动态生成的.制作动态网页有两种方式,一种方式是在后台拿到前端的html模板,利用后台模板引擎(如ej ...