异常信息

load font error:{}
java.io.IOException: Problem reading font data.
        at java.awt.Font.createFont0(Font.java:1000)
        at java.awt.Font.createFont(Font.java:877)
        at com.anji.captcha.service.impl.ClickWordCaptchaServiceImpl.init(ClickWordCaptchaServiceImpl.java:49)
        at com.anji.captcha.service.impl.DefaultCaptchaServiceImpl.init(DefaultCaptchaServiceImpl.java:33)
        at com.anji.captcha.service.impl.CaptchaServiceFactory.getInstance(CaptchaServiceFactory.java:36)
        at com.gtb.common.config.CaptchaConfig.captchaService(CaptchaConfig.java:57)
        at com.gtb.common.config.CaptchaConfig$$EnhancerBySpringCGLIB$$17f42947.CGLIB$captchaService$0(<generated>)
        at com.gtb.common.config.CaptchaConfig$$EnhancerBySpringCGLIB$$17f42947$$FastClassBySpringCGLIB$$8f11612a.invoke(<generated>)

异常原因

由于该项目是从其他服务器上迁移过来的,迁移过程中没有对logs和temp目录进行打包。而 java.awt.Font.createFont0在加载自定义字体时需要创建临时文件,源码如下:

private static Font createFont0(int fontFormat, InputStream fontStream,
                                    CreatedFontTracker tracker)
        throws java.awt.FontFormatException, java.io.IOException {

        if (fontFormat != Font.TRUETYPE_FONT &&
            fontFormat != Font.TYPE1_FONT) {
            throw new IllegalArgumentException ("font format not recognized");
        }
        boolean copiedFontData = false;
        try {
            //加载字体时在这个位置开始创建临时文件,文件以+~JF开头,.tmp结尾
            final File tFile = AccessController.doPrivileged(
                new PrivilegedExceptionAction<File>() {
                    public File run() throws IOException {
                        return Files.createTempFile("+~JF", ".tmp").toFile();
                    }
                }
            );
            if (tracker != null) {
                tracker.add(tFile);
            }

            int totalSize = 0;
            try {
                final OutputStream outStream =
                    AccessController.doPrivileged(
                        new PrivilegedExceptionAction<OutputStream>() {
                            public OutputStream run() throws IOException {
                                return new FileOutputStream(tFile);
                            }
                        }
                    );
                if (tracker != null) {
                    tracker.set(tFile, outStream);
                }
                try {
                    byte[] buf = new byte[8192];
                    for (;;) {
                        int bytesRead = fontStream.read(buf);
                        if (bytesRead < 0) {
                            break;
                        }
                        if (tracker != null) {
                            if (totalSize+bytesRead > CreatedFontTracker.MAX_FILE_SIZE) {
                                throw new IOException("File too big.");
                            }
                            if (totalSize+tracker.getNumBytes() >
                                CreatedFontTracker.MAX_TOTAL_BYTES)
                              {
                                throw new IOException("Total files too big.");
                            }
                            totalSize += bytesRead;
                            tracker.addBytes(bytesRead);
                        }
                        outStream.write(buf, 0, bytesRead);
                    }
                    /* don't close the input stream */
                } finally {
                    outStream.close();
                }
                /* After all references to a Font2D are dropped, the file
                 * will be removed. To support long-lived AppContexts,
                 * we need to then decrement the byte count by the size
                 * of the file.
                 * If the data isn't a valid font, the implementation will
                 * delete the tmp file and decrement the byte count
                 * in the tracker object before returning from the
                 * constructor, so we can set 'copiedFontData' to true here
                 * without waiting for the results of that constructor.
                 */
                copiedFontData = true;
                Font font = new Font(tFile, fontFormat, true, tracker);
                return font;
            } finally {
                if (tracker != null) {
                    tracker.remove(tFile);
                }
                if (!copiedFontData) {
                    if (tracker != null) {
                        tracker.subBytes(totalSize);
                    }
                    AccessController.doPrivileged(
                        new PrivilegedExceptionAction<Void>() {
                            public Void run() {
                                tFile.delete();
                                return null;
                            }
                        }
                    );
                }
            }
        } catch (Throwable t) {
            if (t instanceof FontFormatException) {
                throw (FontFormatException)t;
            }
            if (t instanceof IOException) {
                throw (IOException)t;
            }
            Throwable cause = t.getCause();
            if (cause instanceof FontFormatException) {
                throw (FontFormatException)cause;
            }
            throw new IOException("Problem reading font data.");
        }
    }

开始以为是字体库问题:运行命令

fc-list

yum install fontconfig

后并没有解决这个问题。然后不断的翻源码,怀疑是临时文件的问题。查看Tomcat下bin/catalina.sh 文件找到java 的JVM临时目录java.io.tmpdir的配置是CATALINA_TMPDIR=“$CATALINA_BASE”/temp
CATALINA_BASE指向的是Tomcat安装目录,由于是迁移过来的没有对temp目录做打包。在新建temp目录后启动正常

mkdir temp

在此记录一下这问题。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐