ImageIO.read(URL) 需要永远加载图像
ImageIO.read(URL) takes forever loading an image
我正在使用 JavaEE-Techniques 实现 REST-API,移动应用程序将访问该技术并用一些 JSON-数据响应它们要求。到目前为止一切正常,直到我们注意到一个查询花费了异常长的时间。起初我以为它是一个 'complex' 数据库查询,它是 运行 这么长,但经过一些调试它指出通过 [=65= 访问检索到的数据的缩略图](URL) 方法是请求 take 所以 long.
的原因
通过数据库查询,我正在检索指向我要检索的(缩略图)图像数据的 URL。在创建对象的 JSON-Data 以将其发送回客户端之前,我要将图像编码为 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-param 包含它的主机名,但也可以通过 "localhost" 或作为文件访问(但它与主机名一起存储在数据库中。为方便起见,我没有转换它,有还发现了非常方便的 ImageIO.read(URL) 方法。)因此网络也不应该成为瓶颈。
非常奇怪的行为是,ImageIO 在第一次调用 时需要 10 - 60 秒才能通过 url 访问图像。 之后(同一客户端请求中的多个结果数据)只需要大约 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 class 注释为无状态 bean 并将其注入服务 class。也许这可以改进一些缓存/连接过程或支持一些并行执行/线程等(还没有尝试过)。
也许有人在使用 ImageIO 时遇到了类似的问题或发现了明显的错误行为并可以分享他的知识。
谢谢您,并致以最诚挚的问候!
P.S.: 整个代码是 运行 在 Wildlfy (8.2.Final and on Java 8 ) 应用服务器。因此,在使用 ImageIO 时手动启动一些线程(我研究中的一些帖子的建议)不是一个好主意。
正如它所指出的,这不是 ImageIO 的直接问题,而且它与缓慢/错误配置的 Apache 服务器有关。只需重新启动提供图像的 Apache 服务器即可解决我的问题。
我正在使用 JavaEE-Techniques 实现 REST-API,移动应用程序将访问该技术并用一些 JSON-数据响应它们要求。到目前为止一切正常,直到我们注意到一个查询花费了异常长的时间。起初我以为它是一个 'complex' 数据库查询,它是 运行 这么长,但经过一些调试它指出通过 [=65= 访问检索到的数据的缩略图](URL) 方法是请求 take 所以 long.
的原因通过数据库查询,我正在检索指向我要检索的(缩略图)图像数据的 URL。在创建对象的 JSON-Data 以将其发送回客户端之前,我要将图像编码为 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-param 包含它的主机名,但也可以通过 "localhost" 或作为文件访问(但它与主机名一起存储在数据库中。为方便起见,我没有转换它,有还发现了非常方便的 ImageIO.read(URL) 方法。)因此网络也不应该成为瓶颈。
非常奇怪的行为是,ImageIO 在第一次调用 时需要 10 - 60 秒才能通过 url 访问图像。 之后(同一客户端请求中的多个结果数据)只需要大约 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 class 注释为无状态 bean 并将其注入服务 class。也许这可以改进一些缓存/连接过程或支持一些并行执行/线程等(还没有尝试过)。
也许有人在使用 ImageIO 时遇到了类似的问题或发现了明显的错误行为并可以分享他的知识。
谢谢您,并致以最诚挚的问候!
P.S.: 整个代码是 运行 在 Wildlfy (8.2.Final and on Java 8 ) 应用服务器。因此,在使用 ImageIO 时手动启动一些线程(我研究中的一些帖子的建议)不是一个好主意。
正如它所指出的,这不是 ImageIO 的直接问题,而且它与缓慢/错误配置的 Apache 服务器有关。只需重新启动提供图像的 Apache 服务器即可解决我的问题。