【问题标题】:ImageIO.read(URL) takes forever loading an imageImageIO.read(URL) 永远加载图像
【发布时间】:2016-10-08 12:57:00
【问题描述】:

我正在使用 JavaEE-Techniques 实现一个 REST-API,它将被移动应用程序访问并使用一些 JSON-Data 来响应他们的请求。到目前为止一切正常,直到我们注意到查询花费了异常长的时间。起初我认为这是一个运行了很长时间的“复杂”数据库查询,但经过一些调试后它指出通过 ImageIO.read(URL) 方法访问检索到的数据的缩略图是请求采取如此长时间的原因。

通过数据库查询,我正在检索一个指向我想要检索的(缩略图)图像数据的 URL。在创建对象的 JSON 数据以将其发送回客户端之前,我将把图像编码为 Base64 字符串。

我的代码如下所示(我知道它现在不是很好,但这就是我现在让它工作的方式,我知道我可以使用 try-resource 块并且可能应该将日志记录转换为日志级调试,我要去):

public class Base64Utility
{
    public static String encodeBase64FromUrl(final URL pImageUrl, final ThumbnailPictureDbo pThumbnailPicture)
    {
        BufferedImage img = null;
        String base64EncodedImageString = null;
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] imageBytes = null;

        try
        {
            logger.info("Starting to convert the image!");

            final Long start = System.currentTimeMillis();

            // The Sucker!
            img = ImageIO.read(pImageUrl);
            final Long imageLoadTime = System.currentTimeMillis() - start;
            logger.info("Loaded Image from url {} in: {}", pImageUrl, imageLoadTime);

            final Long start2 = System.currentTimeMillis();
            ImageIO.write(img, "png", bos);
            imageBytes = bos.toByteArray();

            final Long imageWriteTime = System.currentTimeMillis() - start2;
            logger.info("Wrote Image in: {}", imageWriteTime);
            bos.close();

            final Long start3 = System.currentTimeMillis();
            // What to return when img == null?!
            base64EncodedImageString = imageBytes != null ? Base64.getEncoder()
                .encodeToString(imageBytes) : "";

            final Long imageEncodeTime= System.currentTimeMillis() - start3;
            logger.info("Encoded Image in: {}", imageEncodeTime);

            pThumbnailPicture.setBase64EncodedImage(base64EncodedImageString);

            logger.info("Finished converting the image!");
            logger.info("Took total time: " + (System.currentTimeMillis() - start));
            return base64EncodedImageString;
        }
        catch (final IOException e)
        {
            e.printStackTrace();
        }
    return base64EncodedImageString;
}

图像托管在与数据库所在的同一台机器上,代码在上运行。因此 URL 参数包含它的主机名,但也可以通过“localhost”或作为文件访问(但它与主机名一起存储在数据库中。为方便起见,我没有转换它,还找到了非常方便的 ImageIO .read(URL) 方法。)因此网络也不应该是瓶颈。
非常奇怪的行为是,ImageIO 在第一次调用时通过 url 访问图像需要 10 - 60 秒之后(同一客户端请求中的多个结果数据)只需要大约 100 毫秒
在一个全新的请求上,它的行为是相同的(第一次调用异常长,而接下来的调用非常短)。这是一些日志的输出(在客户端的一个请求期间!):

Starting to convert the image!
Loaded Image from url <URL>/Logo-KF-transparent-1500-1024x992.png in: 21810
Wrote Image in: 973
Encoded Image in: 3
Finished converting the image!
Took total time: 22787

Starting to convert the image!
Loaded Image from url <URL>/IMG_1026_905.jpg in: 157
Wrote Image in: 440
Encoded Image in: 7
Finished converting the image!
Took total time: 605

Starting to convert the image!
Loaded Image from url <URL>/WorkshopS2_KaffeeFabrik_1200x800-500x300.jpg in: 23
Wrote Image in: 101
Encoded Image in: 2
Finished converting the image!
Took total time: 127

Starting to convert the image!
Loaded Image from url <URL>/kaffeezumabnehmen.jpg in: 226
Wrote Image in: 98
Encoded Image in: 4
Finished converting the image!
Took total time: 329

Starting to convert the image!
Loaded Image from url <URL>/kaffee_apa.jpg in: 12
Wrote Image in: 60
Encoded Image in: 2
Finished converting the image!
Took total time: 75

因此,行为不依赖于 图像也不依赖于 图像的格式,它始终是第一次访问/加载长!有没有人有想法或解决方案?我对另一种读取/加载图像的方法也很好,这只是我的第一次尝试,也是我自己研究的第一个结果。也许有完全不同的更好的方法来做到这一点。

我以这种方式从 RequestScoped-CDI bean 调用实用程序:

@RequestScoped
public class LocationPersistenceServiceImpl implements LocationPersistenceService
{
    // Some other attributes and methods...

    @Override
    public List<LocationData> findLocations(final QueryParams[] pQueryParams)
    {
        final QueryBuilder<LocationDbo> qb = new QueryBuilder<>(pQueryParams, emf, LocationDbo.class);
        final List<LocationDbo> locationDboQueryResults = qb.getResultList();
        for (LocationDbo retrievedLocDbo : locationDboQueryResults)
        {
            retrievedLocDbo = enhanceRetrievedLocationDboMetaInformation(retrievedLocDbo);
        }
        return dboToData.convert(locationDboQueryResults);
    }

    private LocationDbo enhanceRetrievedLocationDboMetaInformation(LocationDbo pRetrievedLocDbo)
    {
        final List<PostMetaInformationDbo> postMetaInfos = pPs.retrievePostMetaInfomationsById(pRetrievedLocDbo.getPostId());
        pRetrievedLocDbo = addRetrievedLocationMetaInfosFromLocationPost(pRetrievedLocDbo, postMetaInfos);
        return pRetrievedLocDbo;
    }

    private LocationDbo addRetrievedLocationMetaInfosFromLocationPost(final LocationDbo pLocDbo, final List<PostMetaInformationDbo> pPostMeta)
    {
        for (final PostMetaInformationDbo p : pPostMeta)
        {
            // Some code...
        }
        if ((pLocDbo.getThumbnailPicture() != null) && (!StringUtils.isBlank(pLocDbo.getThumbnailPicture()
            .getGuid())))
        {
            Base64Utility.encodeBase64FromUrl(pLocDbo.getThumbnailPicture()
                .getGuid(), pLocDbo.getThumbnailPicture());
        }
        return pLocDbo;
    }
}

我的另一个想法是将 Base64Utility 类注释为无状态 bean 并将其注入到服务类中。也许这可以改进一些缓存/连接过程或支持一些并行执行/线程等(还没有尝试过)。

也许有人在使用 ImageIO 时遇到了类似的问题或发现了明显的不当行为,并且可以分享他的知识。

谢谢你和最好的问候!

P.S.:整个代码在 Wildlfy(8.2.Final 和 Java 8)应用服务器中运行。因此,在使用 ImageIO 时手动启动一些线程(我的研究中的一些帖子建议)不应该是一个好主意。

【问题讨论】:

  • 您是否尝试使用网络浏览器或其他工具(curl、wget 等)加载图像 URL,看看它们是否加载得更快?无论如何,后续的读取速度会更快,因为 URL 正在被缓存。此外,ByteArrayOutputStream.toByteArray() 从不 返回 null。
  • 当然可以。但我可能被愚弄了。使用 firefox 打开 URL 似乎可以立即工作 -> Img 可能已被缓存。在私人标签中访问 URL 花了我 27 秒。编辑:在远程机器(托管图像)上的 wget 也需要 10 - 20 秒。
  • 投票结束这个问题,因为真正的问题似乎是在服务器和/或网络 I/O 上生成图像,与 ImageIO.read 没有直接关系。

标签: java image base64 wildfly-8 javax.imageio


【解决方案1】:

正如它所指出的,这不是 ImageIO 的直接问题,而且它与缓慢/错误配置的 Apache 服务器有关。只需重新启动提供图像的 Apache 服务器即可解决我的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 2019-05-24
    • 2023-03-23
    • 1970-01-01
    • 2018-05-13
    • 2019-12-07
    相关资源
    最近更新 更多