深入理解spring(深入理解Spring Cloud一(4)Bean中的属性是如何刷新的)

:暂无数据 2026-04-02 20:00:02 0
老铁们,关于深入理解spring,你可能听过不少说法。今天,咱们就坐下来好好聊聊深入理解Spring Cloud一(4)Bean中的属性是如何刷新的,保证让你豁然开朗。

本文目录

深入理解Spring Cloud一(4)Bean中的属性是如何刷新的

上文说到Nacos配置中心文件变动通知,本文继续讲解后续动作,Bean中的属性值是如何刷新的。

要想动态刷新Bean中的属性值,Class上必须注解@RefreshScope,这个注解又是干什么的呢。

我们看一下@RefreshScope的源码,实际就是@Scope("refresh"),代理方式使用CGLIB。

@Scope注解的解析方法如下,解析出Bean的scope和代理模式。

最终调用ContextRefresher的refresh方法。

refreshEnvironment,刷新Environment里面的属性值,然后发布EnvironmentChangeEvent事件,里面包括了变动的key。我们可以通过**这个事情,获得变动的配置key。

addConfigFilesToEnvironment,通过SpringApplication的构建,重新走一遍配置加载流程,获取所有的配置,然后更新到当前Context的Environment中。

至此Context的Environment已经是最新的了,但是Bean中的属性值还没有被刷新。

设置最新的Environment后,继续调用RefreshScope.refreshAll(),将@RefreshScope注解的Bean,进行destroy,然后发布RefreshScopeRefreshedEvent事件。

我们看一下destroy,并没有看到刷新Bean属性值的方法。

this.cache.clear()也没有刷新Bean属性值的方法,只是最终由StandardScopeCache实现的,使用ConcurrentMap做缓存清理。

我们需要了解AbstractBeanFactory中scope的Bean是如何创建的,才能解开谜团。

Scope是一个接口,RefreshScope是其中的一个实现,这里实际就是调用RefreshScope的get(String name, ObjectFactory《?》 objectFactory)方法创建Bean。RefreshScope继承GenericScope,最终调用代码如下

我们看到创建的时候有this.cache.put(),配置刷新Bean销毁的时候有this.cache.clear(),玄机就在这里。

如果缓存中有BeanLifecycleWrapper对象则返回旧对象,否则放入缓存中。

我们再看BeanLifecycleWrapper.getBean()方法,标准的单例写法,双重检查加锁创建bean。

至此我们了解到,通过RefreshScope创建bean后,会进行缓存(通过BeanLifecycleWrapper实现),如果没有刷新配置,则一直使用缓存,当配置刷新时清除缓存,RefreshScope会重新创建bean,这时bean中的属性就是最新的了。

1.通过临时SpringApplication的构建,重新走一遍配置加载流程,获取所有的配置,然后更新到当前Context的Environment中。

2.通过RefreshScope控制Bean的生命周期,在配置刷新的时候,重建Bean对象。

成为一个Java的架构师要学习哪些知识

给您一张图,你自己去理解吧。我是一枚Java 8年。

我的网站:

***隐藏网址***

多多交流

spring怎么通过beanfactory来管理对象

首先先来理解spring中对JavaBean的管理机制。Spring容器所管理的bean对象都是由beanFacotry工厂来实例化,所以要使用pring容器中bean实例对象,必须该类也是由spring容器所管理,否则无法从bean工厂中得到bean实例对象。
Struts 最新版本中是由 我们先抛开struts2专门来看spring,那么我们就从spring标准配置文件来说起,如果你要向某个由spring管理的对象中注入一个对象,我们该如何去做呢?举例说明:如果由两个对象A、B,现在需要在B对象中使用A对象,那么我们通过什么方式将A注入到B中去呢?首先A、B两个对象都必须是由spring容器来管理,那么我们就需要在配置文件定义property 属性来注入,现在A、B都有spring容器来管理的,那么我如何得到其中A对象呢?因为AB对象都是由spring容器来创建的,所以要想得到A对象,就首先得到BeanFactory---》GetA(),然后才能拿到A,这时A指向B对象的引用才有值,才能把A注入到B中。
1、 第一种不推荐的方式:
在spring配置文件中配置如下:Java代码
定义一个类变量(静态的static,这个类的所有实例共享的变量),启动服务器时,初始化spring时就创建了BeanFactory,在创建BeanFacotry时,就实例化了所有对象。也就说也就创建了一个roleAssignmentHandler03 对象,放到了它自己容器的那块内存中,这个对象拥有一个指向userService的引用,因为我在这里定义的是类变量。等下次在创建这个对象时,在这个类变量中同样是有值。但是这种方法并不推荐,这种方式有点浪费内存空间,spring已经给我们创建了对象,但是我们并没有去使用它。
Java代码publicclassRoleAssignmentHandler03implementsAssignmentHandler{ privatestaticUserServiceuserService; publicvoidsetUserService(UserService_userService){ userService=_userService; } ……public class RoleAssignmentHandler03 implements AssignmentHandler {private static UserService userService;public void setUserService(UserService _userService) {userService = _userService;}……
2、 第二种不推荐的方式:
我不能向往常做测试那样通过new ClassPathXmlApplicationContext("");来创建它,我们需要从当前环境中去拿,那么从什么地方去拿呢?那么就得明白它是如何创建的,由谁来创建并管理的?在服务器启动时,它就会初始化web.xml中的linstener配置信息,创建一个Bean’Factroy对象,并把这个对象放到了ServletContext中,我们可以利用spring中的一个工具类来得到ServletContext中的BeanFactory对象,但是并推荐,因为ServletActionContext是Struts中的,在业务逻辑中过分依赖于展现层的内容,JBPM是不依赖于展现层内容的,也不推荐于依赖关系的存在。
Java代码BeanFactoryfactory=WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext()); UserServiceuserService=factory.getBean("userService");BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());UserService userService = factory.getBean("userService");
3、 第三种并不推荐的方式
在项目开发中采用SSH与JBPM集成时,用到了一个第三方的集成包,我们可以从这里得到解决方案,(采用jbpm3.1所以其第三方集成包为spring-modules-jbpm31.jar)在其文档(jbpm31.html)中可以了解到,采用如下配置:
流程定义文件配置Java代码 roleAssignmentHandler03 roleAssignmentHandler03
在spring配置文件中可以这样定义如下Java代码
4、 第四种方式:
回过头来,我们接着继续思考从BeanFactory中去获得,流程定义文件并不去修改它,这样就不会破坏它的灵活性,那么接下来要分析的问题就是如何来获得BeanFactory呢?那就得深入了解一下spring,现在来看一个问题:在一个单例中如何获得一个非单例的对象呢?也就是将B注入到A中 A是单例,但是B不是单例,直接采用Resource或在配置文件利用property注入的话,是无法实现的,只能将B变成一个单例对象来使用。那么我们在单例对象中如何动态获取依赖对象呢?有一种方式就从它的BeanFactory中去获得其对象,如何在由spring管理的对象中拿到BeanFactory呢?也就是说在容器实例对象中访问容器本身,在spring中有这样一个BeanFactoryAware接口,在这个接口有个setBeanFactory(BeanFactory f)方法,我们可以实现该接口,重写这个方法,来得到我们BeanFactory,从中得到动态的得到BeanFactory中实例对象,但是放到jbpm中handler类中来使用,还是无法实现的,因为在这里它不是有spring来管理的,所以即使实现BeanFactory接口,重写其方法,但是无法将BeanFactory设置上值的,因为它是由spring来管理的,所以我无法从一个不是spring所管理的bean中去注入spring所提供的bean对象。但是我们可以通过另一种途径来解决这个问题:创建一个辅助类BeanFactroyHelper类,让它来实现刚才这个BeanFactoryAware接口,具体如下:Java代码publicclassBeanFactoryHelperimplementsBeanFactoryAware{ privatestaticBeanFactoryfactory; publicvoidsetBeanFactory(BeanFactoryf)throwsBeansException{ factory=f; } publicstaticBeanFactorygetFactory(){ returnfactory; } }public class BeanFactoryHelper implements BeanFactoryAware {private static BeanFactory factory;public void setBeanFactory(BeanFactory f) throws BeansException {factory = f;}public static BeanFactory getFactory(){return factory;}}
然后,让上面这个类纳入spring的管理,在spring中配置如下:Java代码
最后在我们handler类中,直接使用就可以了Java代码BeanFactoryfactory=BeanFactoryHelper.getFactory();BeanFactory factory = BeanFactoryHelper.getFactory();
这种方式可以,但是我并采用这种方式,因为第四种方式已经有人给我做了。所以我们就不需要在重复做这些类似的工作了。所以这种方式我也不会采用。
5、 第五种方式:
通过上面所说的方式,在spring-modules.jar这个第三方集成包开发人中已经采用类似的方式实现了。那么他们是如何实现的呢?这就需要来了解一下jbpmHandlerProxy的基本原理,在JbpmHandlerProxy类中实现了ActionHandler, AssignmentHandler, DecisionHandler, TaskControllerHandler等接口,在实现不同的接口会调用不同它的不同的方法execute、assign、decide…
ServiceLocator,在spring中也提供了一个ServiceLocator这种设计模式的一个接口BeanFactoryLocator、 BeanFactoryReference接口,要想详细了解其内部机制需要我们进一步花费精力去解析其源码了。(在这里就不详细去分析了)这里我只是了解jbpmFactoryPorxy类中实现机制的大体思想,所以下面我就针对在代理类中的具体实现思想大体说一下:在JbpmHandlerProxy类中得到BeanFactory对象,主要是通过JbpmFactoryLocator来得到BeanFactoryReference,通过BeanFactoryReference来得到Factory。那么在JbpmHandlerProxy类中的JbpmFactoryLocator是从哪里得到的呢?查看源码可以得知在其JbpmFactoryLocator类下有个setBeanFactory()方法,那么这个方法是有谁调用的呢?通过查看得知是LocalJbpmConfigurationFactoryBean类来调用的。主要分析图如下:
以上就jbpmFactoryProxy中内部机制。
下面我就来说一下具体解决方案是:
首先通过利用jbpmFactoryProxy的实现类中retrieveBeanFactory方法的具体实现方式,来得到jbpm中已经注入的BeanFactory对象,下面我将进一步进行封装来实现自动注入的功能。
先贴出在jbpm的handler类中的具体使用,和在spring中使用Bean对象一样使用。
Java代码/** *是由BaseAutowire自动注入 */@ResourceprivateUserServiceuserServce;/*** 是由BaseAutowire自动注入*/@Resourceprivate UserService userServce;下面一段代码将是所抽取出来的基类:Java代码/** *自动注入BeanFactory基类 *@authorlzh * */publicclassBaseAutowire{ /** *在调用子类的时会自动调用 *在构造方法中调用retrieveBeanFactory()方法得到BeanFactory对象 *利用它的实现接口设置将该自身设置为自动注入到子类中 */publicBaseAutowire(){ ((AutowireCapableBeanFactory)retrieveBeanFactory()) .autowireBeanProperties(this,AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,true); } protectedBeanFactoryretrieveBeanFactory(){ BeanFactoryLocato***ctoryLocator=newJbpmFactoryLocator(); BeanFactoryReferencefactory=factoryLocator.useBeanFactory(null); if(factory==null) thrownewIllegalArgumentException("nobeanFactoryfoundunderkey="+null); try{ returnfactory.getFactory(); } finally{ factory.release(); } } }/*** 自动注入BeanFactory基类* @author lzh**/public class BaseAutowire {/*** 在调用子类的时会自动调用* 在构造方法中调用retrieveBeanFactory()方法得到BeanFactory对象* 利用它的实现接口设置将该自身设置为自动注入到子类中*/public BaseAutowire() {((AutowireCapableBeanFactory)retrieveBeanFactory()).autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);}protected BeanFactory retrieveBeanFactory() {BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();BeanFactoryReference factory = factoryLocator.useBeanFactory(null);if (factory == null)throw new IllegalArgumentException("no beanFactory found under key=" + null);try {return factory.getFactory();}finally {factory.release();}}}

如果你还想了解更多这方面的信息,记得收藏关注本站。
本文编辑:admin

本文相关文章:


springcloud各组件详解(18.SpringCloud有哪些组件)

springcloud各组件详解(18.SpringCloud有哪些组件)

您是否正在为搞不清springcloud各组件详解和18.SpringCloud有哪些组件的关系而烦恼?恭喜,这篇干货就是您的“及时雨”。

2026年3月30日 10:40

更多文章:


编程猫下载最新版本(湛江哪里有学编程的)

编程猫下载最新版本(湛江哪里有学编程的)

老铁们,关于编程猫下载最新版本,你可能听过不少说法。今天,咱们就坐下来好好聊聊湛江哪里有学编程的,保证让你豁然开朗。

2026年4月2日 21:20

美图秀秀怎么切割图片?用ppt切割图片的方法

美图秀秀怎么切割图片?用ppt切割图片的方法

“图片切割”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看美图秀秀怎么切割图片?用ppt切割图片的方法!

2026年4月2日 21:00

vba将计算结果存入数组(vba中怎样将数组arr1的结果存入数组arr中)

vba将计算结果存入数组(vba中怎样将数组arr1的结果存入数组arr中)

本文旨在为您说清楚两件事:一是vba将计算结果存入数组到底是什么,二是如何理解vba中怎样将数组arr1的结果存入数组arr中。内容不长,但都是干货,希望能对您有所帮助。

2026年4月2日 20:40

冒泡排序法c++(冒泡排序法c++求数组中的最大值)

冒泡排序法c++(冒泡排序法c++求数组中的最大值)

正如一位名家所言:“弄懂冒泡排序法c++求数组中的最大值,是通往冒泡排序法c++殿堂的捷径。” 今天,我们就来走一走这条捷径。

2026年4月2日 20:20

深入理解spring(深入理解Spring Cloud一(4)Bean中的属性是如何刷新的)

深入理解spring(深入理解Spring Cloud一(4)Bean中的属性是如何刷新的)

老铁们,关于深入理解spring,你可能听过不少说法。今天,咱们就坐下来好好聊聊深入理解Spring Cloud一(4)Bean中的属性是如何刷新的,保证让你豁然开朗。

2026年4月2日 20:00

进入linux系统命令(重新启动linux系统命令)

进入linux系统命令(重新启动linux系统命令)

大家好,如果您对进入linux系统命令还心存疑问,别着急,今天这篇文章就将围绕重新启动linux系统命令为您展开详细解说。

2026年4月2日 19:40

pip不是内部或外部命令怎么解决(这个Python语句为什么提示语法错误)

pip不是内部或外部命令怎么解决(这个Python语句为什么提示语法错误)

最近,关于pip不是内部或外部命令怎么解决的讨论又热了起来。今天咱们不绕弯子,直接切入大家最关心的这个Python语句为什么提示语法错误问题,看看它为何如此重要。

2026年4月2日 19:20

域名空间是什么?域名和空间有什么区别以及关联

域名空间是什么?域名和空间有什么区别以及关联

有没有觉得域名空间听起来很高深?别怕,今天我们就把它和域名空间是什么一起,拆解成易懂的小知识点。

2026年4月2日 19:00

openstack核心模块(openstack指的是什么包含什么)

openstack核心模块(openstack指的是什么包含什么)

各位老铁们,大家好,今天由我来为大家分享openstack核心模块,以及openstack指的是什么包含什么的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

2026年4月2日 18:40

培训机构老师何去何从(课外培训受到政策的冲击,教培机构的老师该何去何从)

培训机构老师何去何从(课外培训受到政策的冲击,教培机构的老师该何去何从)

很多朋友初次接触培训机构老师何去何从可能会觉得有点陌生,这很正常。今天这篇文章,咱们就一起把课外培训受到政策的冲击,教培机构的老师该何去何从这事儿聊透,希望能帮您理清思路。

2026年4月2日 18:20

最近更新

热门文章

用bootstrap做的网站(Bootstrap简介)
2026-04-02 05:40:01 浏览:0
matlab求基础解系(matlab  中的 null(A,’r’)命令中的‘r‘是什么)
2026-04-02 13:40:02 浏览:0
parameters函数(英语parameter和argument作为参数的意思区别是什么)
2026-04-02 16:20:02 浏览:0
currency converter xe(苹果为什么没有下载xe会出现xecurrency这个软件)
2026-04-02 08:20:01 浏览:0
标签列表