Showing posts with label spring-loading-beans. Show all posts
Showing posts with label spring-loading-beans. Show all posts

Saturday, 11 June 2011

BeanFactory in Spring

As its name implies, a bean factory is an implementation of the Factory design pattern. That is, it is a class whose responsibility is to create and dispense beans. The BeanFactory is the actual container which instantiates, configures, and manages a number of beans. These beans typically collaborate with one another, and thus have dependencies between themselves. When a bean factory hands out objects, those objects are fully configured, are aware of their collaborating objects, and are ready to use.

BeanFactory is a workhorse that initializes beans and calls their lifecycle methods. It should be noted that most lifecycle methods only apply to singleton beans. Spring cannot manage prototype (non-singleton) lifecycles. This is because, after they’re created, prototypes are handed off to the client and the container loses track of it. For prototypes, Spring is really just a replacement for the “new” operator.

A BeanFactory is represented by the interface org.springframework.beans.factory.BeanFactory, and it is having multiple implementations. The most commonly used simple BeanFactory implementation is org.springframework.beans.factory.xml.XmlBeanFactory. (This should be qualified with the reminder that ApplicationContexts are a subclass of BeanFactory, and most users end up using XML variants of ApplicationContext).

Although for most scenarios, almost all user code managed by the BeanFactory does not have to be aware of the BeanFactory, the BeanFactory does have to be instantiated somehow. This can happen via explicit user code such as:

Resource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
or
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);

or
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = (BeanFactory) appContext;

Beans are lazily loaded into bean factories, meaning that while the bean factory will immediately load the bean definitions (the description of beans and their properties), the beans themselves will not be instantiated until they are needed. While in case of ApplicationContext Interface beans are pre-loaded. See the posts - ApplicationContext in spring and Lazy and pre-loading of beans in spring. os.

More about ApplicationContext in Spring

While the beans package provides basic functionality for managing and manipulating beans, often in a programmatic way, the context package adds ApplicationContext, which enhances BeanFactory functionality in a more framework-oriented style.

A bean factory is fine for simple applications, but to take advantage of the full power of the Spring Framework, you’ll probably want to load your application beans using Spring’s more advanced container, the application context.

Many users will use ApplicationContext in a completely declarative fashion, not even having to create it manually, but instead relying on support classes such as ContextLoader to automatically start an ApplicationContext as part of the normal startup process of a J2EE web-app. Of course, it is still possible to programmatically create an ApplicationContext.

The basis for the context package is the ApplicationContext interface, located in the org.springframework.context package. Deriving from the BeanFactory interface, it provides all the functionality of BeanFactory. To allow working in a more framework-oriented fashion, using layering and hierarchical contexts, the context package also provides the following:

In most cases, you’ll use the ApplicationContext, which adds more enterprise-level, J2EE functionality, such as

  • internationalization (i18n)
  • custom converters (for converting Strings to Object types)
  • event publication/notification
  • Access to resources, such as URLs and files
  • Loading of multiple (hierarchical) contexts, allowing each to be focused on one particular layer, for example the web layer of an application.
You could also implement your own ApplicationContext and add support for loading from other resources (such as a database). While many Contexts are available for loading beans, you’ll only need a few, which are listed below. The others are internal classes that are used by the framework itself.

1. ClassPathXmlApplicationContext: Loads context files from the classpath (that is, WEB-INF/classes or WEB-INF/lib for JARs) in a web application. Initializes using a
new ClassPathXmlApplicationContext(path)

where path is the path to the file. The path argument can also be a String array of paths. This is a good context for using in unit tests.

2. FileSystemXmlApplicationContext: Loads context files from the file system, which is nice for testing. Initializes using a
new FileSystemXmlApplicationContext (path)

where path is a relative or absolute path to the file. The path argument can also be a String array of paths.

3. XmlWebApplicationContext: Loads context files internally by the ContextLoaderListener, but can be used outside of it. For instance, if you are running a container that doesn’t load Listeners in the order specified in web.xml, you may have to use this in another Listener. Below is the code to use this Loader.

XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setServletContext(ctx);
context.refresh();


Once you’ve obtained a reference to a context, you can get references to beans using
ctx.getBean(“beanId”)

You will need to cast it to a specific type, but that’s the easy part. Of the above contexts, ClassPathXmlApplicationContext is the most flexible. It doesn’t care where the files are, as long as they’re in the classpath. This allows you to move files around and simply change the classpath.

A side from the additional functionality offered by application contexts, another big difference between an application context and a bean factory is how singleton beans are loaded. A bean factory lazily loads all beans, deferring bean creation until the getBean() method is called. An application context is a bit smarter and preloads all singleton beans upon context startup. By preloading singleton beans, you ensure that they will be ready to use when needed—your application won’t have to wait for them to be created.

Thursday, 2 June 2011

@ContextConfiguration : Getting the context file via annotations in Spring, using JUnit

I was just working on a JUnit test today, and saw the annotation @ContextConfiguration which is good way of providing beans directly in unit test, rather than getting the bean via getBean or any method like we used to do (See here for these methods ). 
To instruct Spring to load beans for the tests in the class, we annotate the class with @ContextConfiguration.
There can be various ways we can use this annotation, lets have a look at it one by one:

No File Specified

@ContextConfiguration – with no parameters, (by Default) looks for the config file as the same name as the class with the suffix “-context.xml“. For example,
Suppose our class is Greeting.java and our context file is spring-context.xml

package com.vaani.contextconfig;

@ContextConfiguration
public class Greeting{
...
}
Well this is equivalent to

@ContextConfiguration("/com/vaani/contextconfig/spring-context.xml")
public class Greeting{

File specified (without a starting Slash)


package com.vaani.contextconfig;
@ContextConfiguration("spring-context.xml")
public class Greeting{

Again this is equivalent to fully qualified package path of Greeting class.

File specified with a Starting Slash

One Simple change can ruin your whole day! Add a Starting Slash to the file name.
package com.vaani.contextconfig;
@ContextConfiguration("/com/vaani/contextconfig/spring-context.xml")
public class Greeting{

We can give fully qualified path of the spring-context file in this annotation.

Multiple Files

Pulling multiple configuration files into the application context for your tests.
@ContextConfiguration(locations = {"spring-context.xml", "other-context.xml"})

Just a tip
Create an XML file per test that imports only the application’s context files that are needed.
This can save test execution time, where we only load beans necessary for these tests.

Sunday, 15 May 2011

Lazy loading vs pre-loading beans in spring framework

Spring framework can instantiate and load related Java objects (called beans) according to a given configuration. An XML file can easily be used to define these bindings. Spring framework supports two different types of loading methods; lazy loading and pre-loading respectively managed by BeanFactory and ApplicationContext containers.

Lazy Loading

A bean is loaded only when an instance of that Java class is requested by any other method or a class. org.springframework.beans.factory.BeanFactory (and subclasses) container loads beans lazily. Following code snippet demonstrate lazy loading, concentrate on how "beans.xml" spring configuration file is loaded by BeanFactory container class.
BeanFactory factory = new XmlBeanFactory(
new InputStreamResource(
new FileInputStream("beans.xml"))); // 1
Employee emp = (Employee) factory.getBean("employeeBean"); // 2


Even though "beans.xml" configuration file is loaded with BeanFactory container in line number 1, none of the beans will be instantiated. Instantiation takes place only at line number 2, where bean called "employeeBean" is requested from container. Since the class is instantiated at getBean() method call, time spend to return this method will vary depending on the instantiated object.




Pre-loading


All beans are instantiated as soon as the spring configuration is loaded by a container. org.springframework.context.ApplicationContext container follows pre-loading methodology.

ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml"); // 1
Employee emp = (Employee) context.getBean("employeeBean"); // 2


As all singleton beans are instantiated by container at line number 1, this line will take some considerable time to complete. However line number 2 will return the bean instance immediately since instances are already available inside the container.

Point to note

Decision to choose one from these two methods would depend solely on application specific requirements. Some applications need to load as soon as possible while many others would probably willing to spend more time at startup but serve client requests faster. However some of the beans defined in a configuration may only be used rarely, so instantiating such classes at start up would not be a wise decision. Similarly, some Java instances would be highly resource consuming; leading not to instantiate at start up.

Thursday, 17 March 2011

Loading beans from a bean descriptor XML file in spring

Consider a java class:
package com.vaani.spring.beans;
class Greeting{
    public Greeting() {
System.out.println(
"Hello");
}
}

Bean Descriptor file
Now consider the bean descriptor file , we can create a file simply like this:

<beans>
<bean id="greetingID" class="com.vaani.spring.Greeting"/>
</beans>


In this example,class “com.vaani.spring.GreetingService” is registered in Spring under name "greetingService".

Now once the descriptor for this bean is written, we can use this bean in any file that needs it.

Example see the main method here:

import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {

ApplicationContext context =
 
                new ClassPathXmlApplicationContext("beans.xml");
Greeting greeting= 
                (Greeting)context.getBean("greetingID");

}
}
So we use getBeans method to get the bean by ID.
 Points to be noted areSuppose if the package name is com.vaani, than we can give path of the beans file in many ways. Have a look at these:
  • If we say:
    ClassPathXmlApplicationContext("beans.xml");
    Than it means it looks into the folder the main file is for beans.xml.
  • if we say
    ClassPathXmlApplicationContext("/com/vaani/beans.xml");
    It is same as
    ClassPathXmlApplicationContext
    (
    "classpath:/com/vaani/beans.xml");
Also see
Further you can load beans lazily or pre loading can be done. See here for that.
Not only this when you are testing your code using JUnit, you can give bean file path via annotations, which is very handy. See here for this.