In this lesson (yes mostly theoretical but we give one example to cover everything at the end) we explore various ways to access resources in spring framework from various locations such as classpath and servletcontext etc.. Existing java.net.URL implementations are not powerful enough to meet the requirements. Spring's Resource interface is meant to be capable of abstracting very low level resources. It has useful methods to see whether resource this object is pointing to exists or not and it is open or not etc.. Following are quite useful methods from Resource interface
getInputStream(): opens the resource and gives us InputStream to read the resource. Developer need to close the stream explicitly.
exists(): checks whether physical resource is existing or not
isOpen(): returns true is resource we are pointing to is a open stream i.e we can NOT read multiple times and after reading it once you need to close to avoid memory leaks.
getDescription(): used for debugging usually contains fully qualified name of the resource.
Even if you are not planning to use spring complete framework, resource abstraction provided by spring can be used as a valuable tool as a replacement of URL implementations. Point to be noted is it DOES nt replace functionality for example, URLResource wraps the underlying resource as URL object only. Wherever possible resource abstraction use underlying objects as URL or File (if suitable).
resources. When you call getResource() on a specific application context, and the location path specified doesn't have a "specific" prefix (such as file://, http://, ftp://, classpath:) then we get resource appropriate to that application context.
So lastly note to remember is if a FileSystemResource that is not associated to a FileSystemXMLApplicationContext then it treats absolute/relative paths as you expect relative to the root of the file system. In case if FileSystemXMLApplicationContext is the resource loader then both absolute/relative paths are to be considered as same (this is due to historical reasons of spring framework design)
getInputStream(): opens the resource and gives us InputStream to read the resource. Developer need to close the stream explicitly.
exists(): checks whether physical resource is existing or not
isOpen(): returns true is resource we are pointing to is a open stream i.e we can NOT read multiple times and after reading it once you need to close to avoid memory leaks.
getDescription(): used for debugging usually contains fully qualified name of the resource.
Even if you are not planning to use spring complete framework, resource abstraction provided by spring can be used as a valuable tool as a replacement of URL implementations. Point to be noted is it DOES nt replace functionality for example, URLResource wraps the underlying resource as URL object only. Wherever possible resource abstraction use underlying objects as URL or File (if suitable).
Built-in Resource Implementations
UrlResource:
It wraps internally java.net.URL object i.e any object usually accessible by URL such as file, http target,ftp target. These will have predefined prefixes such as http:// ftp:// file://, We need to create UrlResource explicitly by calling its constructor or often by PropertyEditors (more later) creates them based on the prefix of the resource. If prefix can not be recognised then property editor assumes them as standard url string and creates a UrlResource. Say if resource path starts with "classpath:" then property editors creates appropriate Resource for that prefix.
ClassPathResource:
This represents a resource available on classpath and uses thread context class loader or a given class loader. This resource internally supports java.io.File if given resource is available on classpath (but not for resource which resides in jar and not been expanded to filesystem). As like above, we need to call explicit constructor to create this or property editors creates these objects if resource path starts with "classpath:"
FileSystemResource:
This represents a resource of type java.io.File and supports resolution as File, URL.
ServletContextResource:
This is a resource implementation for ServletContext resources to interpret relatives paths of web app root directory.
InputStreamResource:
a resource implementation for a given InputStream. Only use this when no other implementations are available. you should mostly prefer ByteArrayResource or any File based resource implementations mostly. Do not use this if you want to read stream multiple times.
ByteArrayResource:
Resource implementation for given byte array and it creates a ByteArrayInputStream for given byte array. Its quite useful to load resource form byte array rather worrying about single-use InputStreamResource.
ResourceLoader
This interface is meant to be implemented by resource which are loading Resource instances.public interface ResourceLoader { Resource getResource(String location); }All application contexts implements this so we can use appl context to load
resources. When you call getResource() on a specific application context, and the location path specified doesn't have a "specific" prefix (such as file://, http://, ftp://, classpath:) then we get resource appropriate to that application context.
Resource template = ctx.getResource("some/resource/path/file.txt");
Above example we did nt give an prefix so based on application context (in this case its classpath xml application context) so you get ClassPathResource. If you execute it against FileSystemXmlApplicationContext then you get a FileSystemResource. On the other-hand you may force to get ClassPathResource irrespective of application context by prefixing the resource by "classpath:" as below:Resource template = ctx.getResource("classpath:some/resource/path/file.txt");
similarly you could ask for URLResource by keeping below prefixes.Resource template = ctx.getResource("file:/some/resource/path/file.txt");
Resource template=ctx.getResource("http://bbc.com/resource/path/file.txt");
ResourceLoaderAware Interface
When spring container identifies a bean class implementing ResourceLoaderAware interface then it itself will be provided as inputs to that class. since ApplicationContext is a ResourceLoader you can implement ApplicationContextAware and acquire ApplicationContext as resource loader and access resources but that not is recommended as we have ResoureLoader specially designed for this otherwise your code will be tightly coupled to spring application context where as ResourceLoader you safely consider as a utility rather part of spring framework. Similarly you could autowire ResourceLoader using @Autowired annotations. Below examples provides us more details:
This show how ApplicationContext is autowired as ResourceLoader.
All application Context implementations use speicial property editors to conver string to Resource objects.So if a bean has a has a property (say called as "template") of type Resource, it can be configured with a simple string for that resource, as follows:Resources as Dependencies:
<bean id="myBean" class="..."> <property name="template" value="some/resource/path/myTemplate.txt"/> </bean>Note that the resource path has no prefix, so because the application context itself is going to be used as the ResourceLoader, the resource itself will be loaded via a ClassPathResource, FileSystemResource, or ServletContextResource (as appropriate) depending on the exact type of the context. You could force it as a special resource by prefixing it with classpath: or file: irrespective of type of ApplicationContext you get either ClassapathResource or URLResource respectively. See the below example:
So lastly note to remember is if a FileSystemResource that is not associated to a FileSystemXMLApplicationContext then it treats absolute/relative paths as you expect relative to the root of the file system. In case if FileSystemXMLApplicationContext is the resource loader then both absolute/relative paths are to be considered as same (this is due to historical reasons of spring framework design)
No comments:
Post a Comment