Loading External Resources

Problem

Sometimes your application may need to read external resources (e.g., text files, XML files, properties file, or image files) from different locations (e.g., a file system, classpath, or URL). Usually, you have to deal with different APIs for loading resources from different locations.

Solution

Spring’s resource loader provides a unified getResource() method for you to retrieve an external resource by a resource path. You can specify different prefixes for this path to load resources from different locations. To load a resource from a file system, you use the file prefix. To load a resource from the classpath, you use the classpath prefix. You may also specify a URL in this resource path. Resource is a general interface in Spring for representing an external resource. Spring provides several implementations for the Resource interface, as shown below. The resourceloader’s getResource() method will decide which Resource implementation to instantiate according to the resource path.

Figure 4-1. Common implementations of the Resource interface

How It Works

Suppose you would like to display a banner at the startup of your shop application. The banner is made up of the following characters and stored in a text file called banner.txt. This file can be put in the current path of your application.

***********************
* Welcome to My Shop! *
***********************

Next you have to write the BannerLoader class to load the banner and output it to the console. As it requires access to a resource loader for loading the resource, it has to implement either the ApplicationContextAware interface or the ResourceLoaderAware interface.

package com.apress.springrecipes.shop;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
public class BannerLoader implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void showBanner() throws IOException {
Resource banner = resourceLoader.getResource("file:banner.txt");
InputStream in = banner.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
String line = reader.readLine();
if (line == null)
break;
System.out.println(line);
}
reader.close();
}
}

By calling the getResource() method from the application context, you can retrieve an external resource specified by a resource path. As your banner file is located in the file system, the resource path should start with the file prefix. You can call the getInputStream() method to retrieve the input stream for this resource. Then you read the file contents line by line with BufferedReader and output them to the console. Finally, you declare a BannerLoader instance in the bean configuration file to display the banner. As you would like to show the banner at startup, you specify the showBanner() method as the initialization method.

<bean id="bannerLoader"
class="com.apress.springrecipes.shop.BannerLoader"
init-method="showBanner" />

Resource Prefixes

The previous resource path specifies a resource in the relative path of the file system. You can specify an absolute path as well. file:c:/shop/banner.txt When your resource is located in the classpath, you have to use the classpath prefix. If there’s no path information presented, it will be loaded from the root of the classpath. classpath:banner.txt If the resource is located in a particular package, you can specify the absolute path from the classpath root. classpath:com/apress/springrecipes/shop/banner.txt Besides a file system path or the classpath, a resource can also be loaded by specifying a URL. http://localhost/shop/banner.txt If there’s no prefix presented in the resource path, the resource will be loaded from a location according to the application context. For FileSystemXmlApplicationContext, the resource will be loaded from the file system. For ClassPathXmlApplicationContext, it will be loaded from the classpath.

Injecting Resources

In addition to calling the getResource() method to load a resource explicitly, you can inject it by using a setter method:

package com.apress.springrecipes.shop;
import org.springframework.core.io.Resource;
public class BannerLoader {

private Resource banner;
public void setBanner(Resource banner) {
this.banner = banner;
}
public void showBanner() throws IOException {
InputStream in = banner.getInputStream();
}
}

In the bean configuration, you can simply specify the resource path for this Resource property. Spring will use the preregistered property editor ResourceEditor to convert it into a Resource object before injecting it into your bean.

<bean id="bannerLoader"
class="com.apress.springrecipes.shop.BannerLoader"
init-method="showBanner">
<property name="banner">
<value>classpath:com/apress/springrecipes/shop/banner.txt</value>
</property>
</bean>