(转)MessageResources. getMessageResources()

本文介绍了Struts框架中资源文件的初始化过程,包括内部资源文件和用户定义的资源文件的初始化方式。通过工厂模式和配置模块实现了资源文件的灵活性与国际化。
资源文件,不过是strus架构内部使用的,还是用户自己定义的资源文件,都是资源文件。之所以会用到资源文件,有两个原因:
一是方面是系统通过配置来实现,那么就会有更好的扩展性,也会更灵活。
另一个方面,可以实现国际化。
所以我们可能会有一个或多个资源配置文件。
那么资源文件到底是如何实现其初始化的呢?
内部资源文件和外部资源文件是分开初始化的,其实是使用了不同的初始化方法。内部资源文件是由init()调用initInternal()直接初始化的,而用户的资源文件是通过配置模块实现的。
内部资源文件如何初始化?
protected void initInternal() throws ServletException {
try {
internal = MessageResources.getMessageResources(internalName);
} catch (MissingResourceException e) {

}
}
上面的方法就实现了内部资源的初始化。
其实很简单,通过资源文件定位,然后返回成一个MessageResources的对象就OK了。
也就是internal变量,以后通过此变量就可以直接取属性的值了。
那么你可能会问,getMessageResources(internalName)又是如何实现取得资源文件的?
我们再跟踪一下:
public synchronized static MessageResources getMessageResources(String config) {

if (defaultFactory == null) {
defaultFactory = MessageResourcesFactory.createFactory();
}
return defaultFactory.createResources(config);
}
很明显,这里面也使用了工厂模式。然后由工厂去生成一个资源MessageResources.
我们可以这样理解,所有的资源其实属于同一类产品,所以他们可是使用同一个工厂。
上面的初始化工厂的部分,我们其实可以看到,
MessageResourcesFactory是一个抽象类,其抽象方法正是createResources(config),
那么他的实现是谁呢?这要问我们的工厂,因为你只有知道了工厂,才会知道产品。
所有我们要先知道,我们初始化了一个什么工厂。
所以我们再看:
public static MessageResourcesFactory createFactory() {

// Construct a new instance of the specified factory class
try {
if (clazz == null)
clazz = RequestUtils.applicationClass(factoryClass);
MessageResourcesFactory factory =
(MessageResourcesFactory) clazz.newInstance();
return (factory);
} catch (Throwable t) {
LOG.error("MessageResourcesFactory.createFactory", t);
return (null);
}

}
其实工厂实由factoryClass决定的。
这在
protected static String factoryClass =
"org.apache.struts.util.PropertyMessageResourcesFactory";
定义了。
所以我们可以看到,其实是PropertyMessageResourcesFactory实现了*.properties文件的初始化。
初始化后的结果在哪?如何去使用呢?
内部资源文件初始化后的结果以MessageResources的实例保存在internal变量上。其定义如下:
protected MessageResources internal = null;
所以只有struts内部能用,我们就不能调用了。
用户的资源文件时如何初始化的呢?
用户的资源文件是通过配置模块ModueConfig来实现的。上面我们已经初始化了一个ModuleConfig了。所以我们就可以来初始化我们的资源文件了。
initModuleMessageResources(moduleConfig);
struts的内部分工也是非常明显的。
ModuleConfig用来管理各个不同的模块的配置。
其实,各个由他管理的模块也有自己的配置。
属性资源文件的配置是就是MessageResourcesConfig
此配置的实例由ModuleConfig来管理,所有由ModuleConfig的实例,可以得到所有属性文件配置的实例。
其实是每一个properties文件,就会对应一个MessageResourcesConfig.
所以我们就可以理解下面的部分代码了。

protected void initModuleMessageResources(ModuleConfig config)
throws ServletException {

MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
for (int i = 0; i < mrcs.length; i++) {
if ((mrcs[i].getFactory() == null)
|| (mrcs[i].getParameter() == null)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ config.getPrefix()
+ "' message resources from '"
+ mrcs[i].getParameter()
+ "'");
}

这个地方得到是工厂的类的名称。如:
"org.apache.struts.util.PropertyMessageResourcesFactory"
通过这个,我们和前面的比较就可以知道,只要是属性文件,就用的都是这个工厂。
String factory = mrcs[i].getFactory();
知道了用哪个工厂之后,就可以实例化了,创建一个工厂了。

MessageResourcesFactory.setFactoryClass(factory);
MessageResourcesFactory factoryObject =
MessageResourcesFactory.createFactory();
factoryObject.setConfig(mrcs[i]);

由工厂生产出一个MessageResources

MessageResources resources =
factoryObject.createResources(mrcs[i].getParameter());
resources.setReturnNull(mrcs[i].getNull());
resources.setEscape(mrcs[i].isEscape());

将解析的结果保存在context 中。

getServletContext().setAttribute(
mrcs[i].getKey() + config.getPrefix(),
resources);
}

}
至此,strtus如何初始化资源文件的过程也完成了。现在我们已经知道了struts初始化属性资源文件的过程。
最终解析的结果是以MessageResources的形式保存在context中。
至于,如何将properties文件解析成MessageResources,详细地过程和实现,再去细细的学习和研究。
你提供的代码是 C# 项目中自动生成的 `Resources` 类的一部分,用于访问**嵌入式资源文件(如字符串、图片、图标等)**。这段代码的作用是 **延迟初始化并返回一个共享的 `ResourceManager` 实例**,以便从 `.resources` 文件中读取资源。 --- ### ✅ 完整解释:`ResourceManager` 属性代码解析 ```csharp /// <summary> /// 返回此类使用的缓存的 ResourceManager 实例。 /// </summary> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlFormStatus.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } ``` #### 🔍 逐行解释: | 代码 | 说明 | |------|------| | `/// <summary>...` | 文档注释,描述该属性用途。 | | `[EditorBrowsable(...Advanced)]` | 表示此成员在智能提示中默认不显示,属于高级用法,避免普通用户误调用。 | | `internal static ResourceManager` | 提供一个内部静态字段,供同一程序集内的资源访问类使用。 | | `if (object.ReferenceEquals(resourceMan, null))` | 检查是否已创建过 `ResourceManager`,实现**懒加载(Lazy Initialization)**。 | | `new ResourceManager("ControlFormStatus.Properties.Resources", typeof(Resources).Assembly)` | 创建 `ResourceManager` 实例:<br> - 第一个参数:资源文件的**完整命名空间名**(通常是 `.resources` 文件编译后的名称)。<br> - 第二个参数:包含资源的程序集(`Assembly`),这里通过 `typeof(Resources).Assembly` 获取当前类所在的程序集。 | | `resourceMan = temp;` | 将新创建的实例赋值给静态字段,后续直接复用,提升性能。 | > 💡 `resourceMan` 是一个私有静态字段,通常定义在类的顶部: > ```csharp > private static global::System.Resources.ResourceManager resourceMan; > ``` --- ### 📁 资源是如何工作的? 当你在 Visual Studio 中添加一个 `.resx` 文件(例如 `Properties\Resources.resx`),编译器会: 1. 将所有资源(字符串、图像、音频等)嵌入到程序集中。 2. 生成一个名为 `Resources.resources` 的二进制文件,并以 `"Namespace.ClassName"` 形式命名。 3. 自动生成 `Resources.Designer.cs` 文件,其中就包括上面这段 `ResourceManager` 属性和各种强类型访问器。 --- ### ✅ 示例:如何使用这个 ResourceManager 加载资源 假设你在 `Resources.resx` 中添加了一张图片 `logo.png` 和一个字符串 `WelcomeMessage`。 #### 自动生成的访问方式(推荐): ```csharp // 强类型访问(由设计器生成) string msg = Resources.WelcomeMessage; Image img = Resources.logo; ``` #### 手动使用 `ResourceManager` 访问: ```csharp var rm = Resources.ResourceManager; string welcome = rm.GetString("WelcomeMessage"); // 获取字符串 Image logo = (Image)rm.GetObject("logo"); // 获取对象(如图片) Console.WriteLine(welcome); ``` --- ### ⚠️ 注意事项 1. **线程安全?** 当前实现不是线程安全的。如果多线程同时首次访问,可能创建多个实例(虽然最终只有一个生效)。建议改为 `static readonly` 或使用 `Lazy<T>`。 2. **改进版本(线程安全 + 更优雅)** ```csharp private static readonly Lazy<global::System.Resources.ResourceManager> lazyResourceManager = new Lazy<global::System.Resources.ResourceManager>(() => new global::System.Resources.ResourceManager("ControlFormStatus.Properties.Resources", typeof(Resources).Assembly)); internal static global::System.Resources.ResourceManager ResourceManager => lazyResourceManager.Value; ``` 这样可以确保线程安全且只初始化一次。 --- ### 🧩 常见问题场景 - ❓ 我删除了资源但仍然能访问? > 清理并重新生成项目,旧的 `.resources` 可能仍嵌在程序集中。 - ❓ 如何添加图片资源并在运行时使用? > 在 `Resources.resx` 中添加图片,然后通过 `Resources.图片名` 直接调用。 - ❓ 为什么路径是 `"ControlFormStatus.Properties.Resources"`? > 这是你项目的根命名空间 + 资源文件相对路径。必须与实际 `.resx` 编译后的名称一致。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值