当前位置: 代码网 > it编程>编程语言>Java > SpringBoot集成I18n国际化文件在jar包外生效问题

SpringBoot集成I18n国际化文件在jar包外生效问题

2024年05月15日 Java 我要评论
i18n无法读取jar包外国际化文件的根本原因首先我们看一下i18n是如何绑定资源文件路径的.绑定资源文件路径的方法是通过下面方法绑定的。resourcebundle.getbundle()我们查看源

i18n无法读取jar包外国际化文件的根本原因

首先我们看一下i18n是如何绑定资源文件路径的.

绑定资源文件路径的方法是通过下面方法绑定的。

resourcebundle.getbundle()

我们查看源码:

最终发现i18n是通过类加载器加载国际化文件的。

然而类加载器是不能加载jar包外的资源文件的,所以我们要改变加载资源文件的方式,我们可以通过file加载jar包外的资源文件。

改变文件读取方式

我们读取源码发现,i18n通过将资源文件读取为stream流存储在resourcebundle对象中,同时i18n存在缓存,将产生的stream对象存储在缓存中。

首先重写下面方法,修改i18n的读取方式。

这样我们就可以读取到jar包外面的资源文件了。

    private class i18nmessagesourcecontrol extends resourcebundle.control {

        @override
        @nullable
        public resourcebundle newbundle(string basename, locale locale, string format, classloader loader, boolean reload)
                throws illegalaccessexception, instantiationexception, ioexception {
            // special handling of default encoding
            if (format.equals("java.properties")) {
                string bundlename = tobundlename(basename, locale);
                final string resourcename = toresourcename(bundlename, "properties");
                inputstream inputstream;
                try {
                    inputstream = accesscontroller.doprivileged((privilegedexceptionaction<inputstream>) () -> getbufferedinputstream(resourcename));
                } catch (privilegedactionexception ex) {
                    throw (ioexception) ex.getexception();
                }
                if (inputstream != null) {
                    string encoding = getdefaultencoding();
                    if (encoding != null) {
                        try (inputstreamreader bundlereader = new inputstreamreader(inputstream, encoding)) {
                            return loadbundle(bundlereader);
                        }
                    } else {
                        try (inputstream bundlestream = inputstream) {
                            return loadbundle(bundlestream);
                        }
                    }
                } else {
                    return null;
                }
            } else {
                // delegate handling of "java.class" format to standard control
                return super.newbundle(basename, locale, format, loader, reload);
            }
        }

    }
    /**
     *  拼接url 并返回输入流
     */
    public inputstream getbufferedinputstream(string resourcename) throws filenotfoundexception {
        string fileurl = system.getproperty("user.dir")+ "/"+ resourcename;
        system.out.println(fileurl+"..*");
        file file = new file(fileurl);
        if (file.exists()) {
            return new fileinputstream(file);
        }
        return  null;
    }

寻找切入点

我们不难发现,resourcebundle.getbundle()这个方法就是为了获取一个resourcebundle对象,所以我们可以重写dogetbundle方法从而获取resourcebundle对象。

public class i18nconfig extends resourcebundlemessagesource {
    private final static logger logger = loggerfactory.getlogger(i18nconfig.class);
    @nullable
    private volatile i18nmessagesourcecontrol control = new i18nmessagesourcecontrol();
    /**
     * obtain the resource bundle for the given basename and locale.
     *
     * @param basename the basename to look for
     * @param locale   the locale to look for
     * @return the corresponding resourcebundle
     * @throws missingresourceexception if no matching bundle could be found
     * @see java.util.resourcebundle#getbundle(string, locale, classloader)
     * @see #getbundleclassloader()
     */
    public resourcebundle dogetbundle(string basename, locale locale) throws missingresourceexception {
        classloader classloader = getbundleclassloader();
        assert.state(classloader != null, "no bundle classloader set");

        i18nmessagesourcecontrol control = this.control;
        if (control != null) {
            try {
                return resourcebundle.getbundle(basename, locale, classloader, control);
            } catch (unsupportedoperationexception ex) {
                // probably in a jigsaw environment on jdk 9+
                this.control = null;
                string encoding = getdefaultencoding();
                if (encoding != null && logger.isinfoenabled()) {
                    logger.info("resourcebundlemessagesource is configured to read resources with encoding '" +
                            encoding + "' but resourcebundle.control not supported in current system environment: " +
                            ex.getmessage() + " - falling back to plain resourcebundle.getbundle retrieval with the " +
                            "platform default encoding. consider setting the 'defaultencoding' property to 'null' " +
                            "for participating in the platform default and therefore avoiding this log message.");
                }
            }
        }

        // fallback: plain getbundle lookup without control handle
        return resourcebundle.getbundle(basename, locale, classloader);
    }

    @scheduled(fixedrate = 180000)
    public  void cleari18ncache() {
        resourcebundle.clearcache(objects.requirenonnull(getbundleclassloader()));
    }
}

最后的cleari18ncache方法

因为i18n存在缓存想要外部资源文件修改后生效,清除缓存,我们读取源码不难发现i18n为我们提供了清理缓存的方法。

我们可以定时清理缓存,也可以通过接口调取手动清理缓存,根据自己需求来定。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com