UML类图
Resource
public interface Resource extends InputStreamSource {
boolean exists();
default boolean isReadable() {
return exists();
}
default boolean isOpen() {
return false;
}
default boolean isFile() {
return false;
}
URL
getURL() throws IOException
;
URI
getURI() throws IOException
;
File
getFile() throws IOException
;
default ReadableByteChannel
readableChannel() throws IOException
{
return Channels
.newChannel(getInputStream());
}
long contentLength() throws IOException
;
long lastModified() throws IOException
;
Resource
createRelative(String relativePath
) throws IOException
;
@Nullable
String
getFilename();
String
getDescription();
}
AbstrctResource
public abstract class AbstractResource implements Resource {
@Override
public boolean exists() {
if (isFile()) {
try {
return getFile().exists();
}
catch (IOException ex
) {
Log logger
= LogFactory
.getLog(getClass());
if (logger
.isDebugEnabled()) {
logger
.debug("Could not retrieve File for existence check of " + getDescription(), ex
);
}
}
}
try {
getInputStream().close();
return true;
}
catch (Throwable ex
) {
Log logger
= LogFactory
.getLog(getClass());
if (logger
.isDebugEnabled()) {
logger
.debug("Could not retrieve InputStream for existence check of " + getDescription(), ex
);
}
return false;
}
}
@Override
public boolean isReadable() {
return exists();
}
@Override
public boolean isOpen() {
return false;
}
@Override
public boolean isFile() {
return false;
}
@Override
public URL
getURL() throws IOException
{
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
}
@Override
public URI
getURI() throws IOException
{
URL url
= getURL();
try {
return ResourceUtils
.toURI(url
);
}
catch (URISyntaxException ex
) {
throw new NestedIOException("Invalid URI [" + url
+ "]", ex
);
}
}
@Override
public File
getFile() throws IOException
{
throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
}
@Override
public ReadableByteChannel
readableChannel() throws IOException
{
return Channels
.newChannel(getInputStream());
}
@Override
public long contentLength() throws IOException
{
InputStream is
= getInputStream();
try {
long size
= 0;
byte[] buf
= new byte[256];
int read
;
while ((read
= is
.read(buf
)) != -1) {
size
+= read
;
}
return size
;
}
finally {
try {
is
.close();
}
catch (IOException ex
) {
Log logger
= LogFactory
.getLog(getClass());
if (logger
.isDebugEnabled()) {
logger
.debug("Could not close content-length InputStream for " + getDescription(), ex
);
}
}
}
}
@Override
public long lastModified() throws IOException
{
File fileToCheck
= getFileForLastModifiedCheck();
long lastModified
= fileToCheck
.lastModified();
if (lastModified
== 0L
&& !fileToCheck
.exists()) {
throw new FileNotFoundException(getDescription() +
" cannot be resolved in the file system for checking its last-modified timestamp");
}
return lastModified
;
}
protected File
getFileForLastModifiedCheck() throws IOException
{
return getFile();
}
@Override
public Resource
createRelative(String relativePath
) throws IOException
{
throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
}
@Override
@Nullable
public String
getFilename() {
return null
;
}
@Override
public boolean equals(@Nullable Object other
) {
return (this == other
|| (other
instanceof Resource &&
((Resource
) other
).getDescription().equals(getDescription())));
}
@Override
public int hashCode() {
return getDescription().hashCode();
}
@Override
public String
toString() {
return getDescription();
}
}
AbstractFileResolvingResource
public abstract class AbstractFileResolvingResource extends AbstractResource {
@Override
public boolean exists() {
try {
URL url
= getURL();
if (ResourceUtils
.isFileURL(url
)) {
return getFile().exists();
}
else {
URLConnection con
= url
.openConnection();
customizeConnection(con
);
HttpURLConnection httpCon
=
(con
instanceof HttpURLConnection ? (HttpURLConnection
) con
: null
);
if (httpCon
!= null
) {
int code
= httpCon
.getResponseCode();
if (code
== HttpURLConnection
.HTTP_OK
) {
return true;
}
else if (code
== HttpURLConnection
.HTTP_NOT_FOUND
) {
return false;
}
}
if (con
.getContentLengthLong() > 0) {
return true;
}
if (httpCon
!= null
) {
httpCon
.disconnect();
return false;
}
else {
getInputStream().close();
return true;
}
}
}
catch (IOException ex
) {
return false;
}
}
@Override
public boolean isReadable() {
try {
URL url
= getURL();
if (ResourceUtils
.isFileURL(url
)) {
File file
= getFile();
return (file
.canRead() && !file
.isDirectory());
}
else {
URLConnection con
= url
.openConnection();
customizeConnection(con
);
if (con
instanceof HttpURLConnection) {
HttpURLConnection httpCon
= (HttpURLConnection
) con
;
int code
= httpCon
.getResponseCode();
if (code
!= HttpURLConnection
.HTTP_OK
) {
httpCon
.disconnect();
return false;
}
}
long contentLength
= con
.getContentLengthLong();
if (contentLength
> 0) {
return true;
}
else if (contentLength
== 0) {
return false;
}
else {
getInputStream().close();
return true;
}
}
}
catch (IOException ex
) {
return false;
}
}
@Override
public boolean isFile() {
try {
URL url
= getURL();
if (url
.getProtocol().startsWith(ResourceUtils
.URL_PROTOCOL_VFS
)) {
return VfsResourceDelegate
.getResource(url
).isFile();
}
return ResourceUtils
.URL_PROTOCOL_FILE
.equals(url
.getProtocol());
}
catch (IOException ex
) {
return false;
}
}
@Override
public File
getFile() throws IOException
{
URL url
= getURL();
if (url
.getProtocol().startsWith(ResourceUtils
.URL_PROTOCOL_VFS
)) {
return VfsResourceDelegate
.getResource(url
).getFile();
}
return ResourceUtils
.getFile(url
, getDescription());
}
@Override
protected File
getFileForLastModifiedCheck() throws IOException
{
URL url
= getURL();
if (ResourceUtils
.isJarURL(url
)) {
URL actualUrl
= ResourceUtils
.extractArchiveURL(url
);
if (actualUrl
.getProtocol().startsWith(ResourceUtils
.URL_PROTOCOL_VFS
)) {
return VfsResourceDelegate
.getResource(actualUrl
).getFile();
}
return ResourceUtils
.getFile(actualUrl
, "Jar URL");
}
else {
return getFile();
}
}
protected boolean isFile(URI uri
) {
try {
if (uri
.getScheme().startsWith(ResourceUtils
.URL_PROTOCOL_VFS
)) {
return VfsResourceDelegate
.getResource(uri
).isFile();
}
return ResourceUtils
.URL_PROTOCOL_FILE
.equals(uri
.getScheme());
}
catch (IOException ex
) {
return false;
}
}
protected File
getFile(URI uri
) throws IOException
{
if (uri
.getScheme().startsWith(ResourceUtils
.URL_PROTOCOL_VFS
)) {
return VfsResourceDelegate
.getResource(uri
).getFile();
}
return ResourceUtils
.getFile(uri
, getDescription());
}
@Override
public ReadableByteChannel
readableChannel() throws IOException
{
try {
return FileChannel
.open(getFile().toPath(), StandardOpenOption
.READ
);
}
catch (FileNotFoundException | NoSuchFileException ex
) {
return super.readableChannel();
}
}
@Override
public long contentLength() throws IOException
{
URL url
= getURL();
if (ResourceUtils
.isFileURL(url
)) {
File file
= getFile();
long length
= file
.length();
if (length
== 0L
&& !file
.exists()) {
throw new FileNotFoundException(getDescription() +
" cannot be resolved in the file system for checking its content length");
}
return length
;
}
else {
URLConnection con
= url
.openConnection();
customizeConnection(con
);
return con
.getContentLengthLong();
}
}
@Override
public long lastModified() throws IOException
{
URL url
= getURL();
boolean fileCheck
= false;
if (ResourceUtils
.isFileURL(url
) || ResourceUtils
.isJarURL(url
)) {
fileCheck
= true;
try {
File fileToCheck
= getFileForLastModifiedCheck();
long lastModified
= fileToCheck
.lastModified();
if (lastModified
> 0L
|| fileToCheck
.exists()) {
return lastModified
;
}
}
catch (FileNotFoundException ex
) {
}
}
URLConnection con
= url
.openConnection();
customizeConnection(con
);
long lastModified
= con
.getLastModified();
if (fileCheck
&& lastModified
== 0 && con
.getContentLengthLong() <= 0) {
throw new FileNotFoundException(getDescription() +
" cannot be resolved in the file system for checking its last-modified timestamp");
}
return lastModified
;
}
protected void customizeConnection(URLConnection con
) throws IOException
{
ResourceUtils
.useCachesIfNecessary(con
);
if (con
instanceof HttpURLConnection) {
customizeConnection((HttpURLConnection
) con
);
}
}
protected void customizeConnection(HttpURLConnection con
) throws IOException
{
con
.setRequestMethod("HEAD");
}
private static class VfsResourceDelegate {
public static Resource
getResource(URL url
) throws IOException
{
return new VfsResource(VfsUtils
.getRoot(url
));
}
public static Resource
getResource(URI uri
) throws IOException
{
return new VfsResource(VfsUtils
.getRoot(uri
));
}
}
}
ClassPathResource
public class ClassPathResource extends AbstractFileResolvingResource {
private final String path
;
@Nullable
private ClassLoader classLoader
;
@Nullable
private Class
<?> clazz
;
public ClassPathResource(String path
) {
this(path
, (ClassLoader
) null
);
}
public ClassPathResource(String path
, @Nullable ClassLoader classLoader
) {
Assert
.notNull(path
, "Path must not be null");
String pathToUse
= StringUtils
.cleanPath(path
);
if (pathToUse
.startsWith("/")) {
pathToUse
= pathToUse
.substring(1);
}
this.path
= pathToUse
;
this.classLoader
= (classLoader
!= null
? classLoader
: ClassUtils
.getDefaultClassLoader());
}
public ClassPathResource(String path
, @Nullable Class
<?> clazz
) {
Assert
.notNull(path
, "Path must not be null");
this.path
= StringUtils
.cleanPath(path
);
this.clazz
= clazz
;
}
@Deprecated
protected ClassPathResource(String path
, @Nullable ClassLoader classLoader
, @Nullable Class
<?> clazz
) {
this.path
= StringUtils
.cleanPath(path
);
this.classLoader
= classLoader
;
this.clazz
= clazz
;
}
public final String
getPath() {
return this.path
;
}
@Nullable
public final ClassLoader
getClassLoader() {
return (this.clazz
!= null
? this.clazz
.getClassLoader() : this.classLoader
);
}
@Override
public boolean exists() {
return (resolveURL() != null
);
}
@Nullable
protected URL
resolveURL() {
if (this.clazz
!= null
) {
return this.clazz
.getResource(this.path
);
}
else if (this.classLoader
!= null
) {
return this.classLoader
.getResource(this.path
);
}
else {
return ClassLoader
.getSystemResource(this.path
);
}
}
@Override
public InputStream
getInputStream() throws IOException
{
InputStream is
;
if (this.clazz
!= null
) {
is
= this.clazz
.getResourceAsStream(this.path
);
}
else if (this.classLoader
!= null
) {
is
= this.classLoader
.getResourceAsStream(this.path
);
}
else {
is
= ClassLoader
.getSystemResourceAsStream(this.path
);
}
if (is
== null
) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is
;
}
@Override
public URL
getURL() throws IOException
{
URL url
= resolveURL();
if (url
== null
) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
return url
;
}
@Override
public Resource
createRelative(String relativePath
) {
String pathToUse
= StringUtils
.applyRelativePath(this.path
, relativePath
);
return (this.clazz
!= null
? new ClassPathResource(pathToUse
, this.clazz
) :
new ClassPathResource(pathToUse
, this.classLoader
));
}
@Override
@Nullable
public String
getFilename() {
return StringUtils
.getFilename(this.path
);
}
@Override
public String
getDescription() {
StringBuilder builder
= new StringBuilder("class path resource [");
String pathToUse
= this.path
;
if (this.clazz
!= null
&& !pathToUse
.startsWith("/")) {
builder
.append(ClassUtils
.classPackageAsResourcePath(this.clazz
));
builder
.append('/');
}
if (pathToUse
.startsWith("/")) {
pathToUse
= pathToUse
.substring(1);
}
builder
.append(pathToUse
);
builder
.append(']');
return builder
.toString();
}
@Override
public boolean equals(@Nullable Object other
) {
if (this == other
) {
return true;
}
if (!(other
instanceof ClassPathResource)) {
return false;
}
ClassPathResource otherRes
= (ClassPathResource
) other
;
return (this.path
.equals(otherRes
.path
) &&
ObjectUtils
.nullSafeEquals(this.classLoader
, otherRes
.classLoader
) &&
ObjectUtils
.nullSafeEquals(this.clazz
, otherRes
.clazz
));
}
@Override
public int hashCode() {
return this.path
.hashCode();
}
}