java 动态加载配置文件_关于Spring配置文件的动态载入的修改

一、

概述

Spring MVC

的开发是基于

action-servlet.xml

进行配置,但不支持开发模式下进行动态的配置文件载入。本文主要是介绍如何修改

Spring

的源代码,使

Spring

支持动态的配置文件更新,让开发变得更加简单。

二、

实现

action-servlet.xml

动态载入

Spring

提取配置文件的思路

:每次

Spring MVC

会在使用前将

XML

文件载入内存中,并生成映射类的实例,放在

Mapping Map

里。然后判断每个请求,如果有其

URL

所对应的映射,则返回其对应的

Action

实例。

修改思路

:将每次得到请求时,让程序重新载入

xml

文件,并实例化其映射,然后放入

Mapping Map

中。

1、

首先是

FrameworkServlet

,他是

DispatcherServlet

的基类。

XML

在载入内存后,放在一个叫

WebApplicationContext

的类中。找到

getWebApplicationContext()

方法,加入以下代码:

ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils

.instantiateClass(getContextClass());

wac.setParent(WebApplicationContextUtils

.getWebApplicationContext(getServletContext()));

wac.setServletContext(getServletContext());

wac.setNamespace(getNamespace());

if

(getContextConfigLocation() !=

null

) {

wac

.setConfigLocations(StringUtils

.tokenizeToStringArray(

getContextConfigLocation(),

ConfigurableWebApplicationContext.

CONFIG_LOCATION_DELIMITERS

));

}

wac.refresh();

this

.

webApplicationContext

= wac;

这样每次再读取

WebApplicationContext

的时候,会重新载入

XML

文件一次。

2、

修改

DispatcherServlet

,这个

Servlet

是处理所有请求的入口。找到

getHandler()

这个方法,他负责找到相应的

Action

,并返回其实例。将代码中的

Iterator it = this.handlerMappings.iterator();

while (it.hasNext()) {

HandlerMapping hm = (HandlerMapping) it.next();

if (logger.isDebugEnabled()) {

logger.debug("Testing handler map [" + hm+ "] in DispatcherServlet with name '" +

getServletName() + "'");

}

handler = hm.getHandler(request);

if (handler != null) {

if (cache) {

request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);

}

return handler;

}

}

改为

initHandlerMappings();

Iterator it =

this

.

handlerMappings

.iterator();

while

(it.hasNext()) {

BeanNameUrlHandlerMapping hm = (BeanNameUrlHandlerMapping) it.next();

if

(

logger

.isDebugEnabled()) {

logger

.debug(

"Testing handler map ["

+ hm+

"] in DispatcherServlet with name '"

+

getServletName() +

"'"

);

}

hm.initApplicationContext();

handler = hm.getHandler(request);

if

(handler !=

null

) {

if

(cache) {

request.setAttribute(

HANDLER_EXECUTION_CHAIN_ATTRIBUTE

, handler);

}

return

handler;

}

}

注解:

1)

其中

BeanNameUrlHandlerMapping

是将强制转换

HandlerMapping

时,用子类代替父类,因为子类提供了一个重新初始化的方法

initApplicationContext()

,调用该方法可以重新载入

WebApplicationContext

,

并刷新

Mapping Map

2)

initHandlerMappings()

DispatcherServlet

初始化

Mapping

的一个方法。在生成

WebApplicationContext

时,程序还会把放在

ApplicationObjectSupport.applicationContext

保存,因此需要重新初始化一次。

3

、修改

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping

类中的

registerHandler()

方法,它的作用是注册

Mapping

,去掉重复性校验,将下面几行代码注释掉。

if (mappedHandler != null) {

throw new ApplicationContextException(

"Cannot map handler [" + handler + "] to URL path [" + urlPath +

"]: there's already handler [" + mappedHandler + "] mapped");

}

三、实现

applicationContext.xml

的动态载入

Spring

实现思路:

applicationContext.xml

Spring

默认的配置文件,它利用配置

ContextLoaderListener

的方式,在应用载入时启动,并将

applicationContext.xml

载入内存中,放在

ServletContext

Attribute

中,保存的方式是一个

WebApplicationContext

类。当每次调用类时,

beanFactory

会调用

WebApplicationContextUtils

中的方法

getWebApplicationContext()

,得到配置信息。

修改方法:

ContextLoaderListener

初始化

WebApplicationContext

时,会利用

ContextLoader

提供的方法

initWebApplicationContext()

进行初始化,我们只需要得到

Listener

的这个

ContextLoader

的实例,并重新调用一个初始化的方法就可以实现重新载入了。

修改步骤:

1

、找到

ContextLoaderListener

类的方法

contextInitialized()

,在

Context

初始化的时候将

ContextLoader

的引用放在

ServletContext

Attribute

中:

public

void

contextInitialized(ServletContextEvent event) {

this

.

contextLoader

= createContextLoader();

this

.

contextLoader

.initWebApplicationContext(event.getServletContext());

event.getServletContext().setAttribute(

"ListenerContextLoader"

,

this

.

contextLoader

);

}

注:

"ListenerContextLoader"

是自定义的名称,可以任意修改。

3、

找到

WebApplicationContextUtils

类的方法

getWebApplicationContext()

,修改第一行代码:

Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

改为:

Object attr =

null

;

ContextLoader cl = (ContextLoader) sc

.getAttribute(

"ListenerContextLoader"

);

if

(cl !=

null

)

attr = cl.initWebApplicationContext(sc);

这样,在每次获取

WebApplicationContext

时,程序会重新载入

applicationContext.xml

一次。

OK

!大功告成,

Enjoy your spring developing

!!!

### 回答1: 在Java,类通常在程序启动时就被加载,而且在运行过程一般不会重新加载。但是,有些情况下可能需要重新加载类,比如在开发过程修改了类的源代码后需要重新加载以测试修改是否生效。 为了重新加载类,可以使用Java的热部署(HotSwap)技术,该技术可以在不停止程序的情况下重新加载已经被加载的类。在Java,可以通过使用一些工具或框架来实现热部署,比如JRebel和Spring Loaded等。 除了热部署之外,还可以通过使用Java的类加载器来重新加载类。Java有多个类加载器,可以通过调用类加载器的reload方法来重新加载已经被加载的类。但是,这种方法比较复杂,需要程序员自己实现。因此,在实际开发,一般更倾向于使用热部署技术来重新加载类。 ### 回答2: 在Java,类的重新加载是指在运行时动态地改变或重新加载一个已经加载过的类。Java虚拟机的类加载机制规定,每个类在内存只能被加载一次,即使重新加载一个类,也不会替换掉原来已经加载的类。 尽管如此,我们可以通过一些技术来实现类的重新加载。一种常见的方式是通过自定义类加载器实现类的重新加载。我们可以自定义一个类加载器,在加载类之前,检查类的更新时间。如果类的源文件或字节码文件发生了改变,就重新载入这个类。 另一种实现类的重新加载的方式是使用Java的热部署技术,如JRebel。JRebel工具可以在不重新启动应用程序的情况下,动态地替换类的字节码,从而实现类的重新加载。 无论使用哪种方式,类的重新加载都需要注意以下几点: 1. 确保重新加载的类与原始类具有相同的类名和包名,否则会导致运行时异常。 2. 在重新加载类之前,需要确保原始类已经被卸载,否则重新加载的类不会生效。 3. 对于正在运行的实例,需要注意处理好类的版本兼容性,避免出现运行时错误。 4. 考虑到性能问题,类的重新加载应该谨慎使用,尽量避免频繁地重新加载类。 总之,Java的类重新加载可以通过自定义类加载器或使用热部署工具实现。但需要注意一些细节问题,确保重新加载的类能够正确地被使用。 ### 回答3: 在Java,类的重新加载是指在程序运行时对类进行更新或替换。Java虚拟机(JVM)默认情况下不支持类的重新加载,但可以通过一些特定的技术实现类的重新加载。 一种常用的实现类重新加载的技术是利用Java的类加载器机制。Java的类加载器可以动态加载类文件,因此可以通过自定义类加载器来实现类的重新加载功能。首先,需要编写一个自定义的类加载器,该加载器负责从指定的路径或URL加载类文件。然后,在程序使用这个自定义的类加载加载需要重新加载的类文件,可以通过修改类文件的路径或URL来实现类的更新。在客户端代码,可以通过调用自定义类加载器的reload方法来重新加载类。 另一种实现类重新加载的技术是使用热部署框架,例如JRebel。这些框架通过在运行时动态地替换类的字节码实现类的重新加载。通过在IDE安装和配置这些框架,可以在开发过程实现代码的即时更新,节省了重新编译和启动的时间。 需要注意的是,类的重新加载也可能会引发一些问题,例如由于类之间的依赖关系导致的加载顺序问题,或者由于类状态的改变导致的运行时错误。因此,在进行类的重新加载时,需要谨慎对待,并进行充分的测试和验证。 总而言之,Java可以通过自定义类加载器或使用热部署框架来实现类的重新加载。这些技术可以加快开发过程的代码更新和调试,提高开发效率。同时,在实际应用需注意类之间的依赖和测试工作,以确保重新加载的类能够正确地运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值