HOW TO USE SPRING FACTORY BEANS IN JAVA DEVELOPMENT

f:id:aegissofttech:20220120183103p:plain

Technology: Spring is the popular framework for java developing applications in an easier way by providing various utility classes. In this post, java outsourcing company experts will explain Spring Factory beans brief. Let’s get an overview of the spring container that offers two methods to create beans. We will also discuss these two methods – beans and factory beans.

Overview: Spring Container provides two ways to create beans, one is default beans by writing xml file or with Java annotations, second is the factory beans.

Spring Factory beans provide plug ability to Spring IOC Container`s bean initialization. If we need complex code to initialize the bean or if we have more no of dependencies then instead of writing large XML we can create a custom factory class and we can plug it into Spring Container.

Factory Beans are mostly used to help spring containers in constructing beans that couldn`t be easily constructed by themselves.

Example: suppose if we want to get the object from JNDI, we can use JNDIFactoryBean so that a reference to bean is created on loading time, whenever is needed we can invoke the getObject() method on factory bean which will return the actual bean reference.

Understanding about Factory Beans:

Spring provides a FactoryBean interface for creating factory beans.

Public interface FactoryBean<T> {            

                                   T getObject() throws Exception;            

                                   Class<?>getObjectType();                  

                                   booleanisSingleton();

}

Let`s understand about methods:

getObject(): this is the main method to return an actual instance of the class, it may be the same instance or a different instance based on implementation, as the spring factory supports both singleton, and prototype design patterns. Before Spring 2.0 while calling the getObject method if the factory bean is not fully initialized (depending on other beans, or circular dependencies) it uses to throw FactoryBeanNotInitializedException exception, but after spring 2.0 if the factory bean is not loaded fully then it will return null, but it is encouraging to throw FactoryBeanNotInitializedException exception if factorybean is not initialized.

getObjectType(): this method will return what type of object that factorybean will create. It will be used in auto wiring of the beans without instantiating it. It may be called before fully initializing the factorybean, it may not depend on the state of the factory bean.

isSingleton(): this is the method that will tell the spring container, the factory bean will return the same instance of the object every time we call getObject() or a different instance of an object.

If this method returns true then the spring container will cache the instance of the bean without invoking the getObject() method every time.

If this method returns false then the spring container will execute getObject() every time, as we call the getObject() method.

Creating beans using Spring Factory Bean interface:

We can create beans in two ways.

  1. We can implement the FactoryBean interface.
  2. Spring provides an abstract implementation of the interface, by extending the class we can write the factorybeans. We need to override the createInstance() method to create the instance and getObjectType() method to tell the return type to the spring container for auto wiring.

If the instance provided by factorybean is singleton then it will return the object instance, otherwise, it will return a proxy of the getObjectType() type of the object.

Some of the existing implementations of spring factory beans:

  1. JndiObjectFactoryBean: for creating beans depending upon JNDI lookup
  2. ProxyFactoryBean: creating beans depends on Spring AOP pointcuts
  3. LocalSessionFactoryBean: for creating Hibernate session factory in Spring IOC Container.

Writing custom Bean factories:

We will implement StudentFactoryBean to produce objects of the type Student.

Student.java 

public class Student {            

              private String firstName;            

              private String lastName;            

              private String email;

public Student(String email) {                        

                                            this.email = email;

}

// getters and setters

}

StudentFactory.java

public class StudentFactory extends AbstractFactoryBean<Student> {               

               private String email;              

               //setters and getters              

               @Override            

                public Class<?>getObjectType() {                        

                returnStudent.class;            

                }            

               @Override            

                protected Student createInstance() throws Exception {                        

                                              return new Student(email);            

                }            

               @Override            

                publicbooleanisSingleton() {                         

                                            return false;            

                      }

}

StudentFactory is the factory bean that will return student objects.

XML Configuration: lets create a spring beans xml file (student-factory-beans.xml) and add the below bean declaration.

 

<bean id="student" class="com.example.StudentFactory"> 

<property name="email" value="test@gmail.com"/> 

</bean>

Testing injected Student object:

@RunWith(SpringJUnit4ClassRunner.class

@ContextConfiguration(locations = { "classpath:spring-factory-beans.xml" }) 

publicclassStudentFactoryXmlTest {            

                            @Autowired

private Student student;    

              @Test

publicvoidtestConstructWorkerByXml() { 

assertThat(student.getEmail(),

equalTo("test@gmail.com"));    

            } 

}

The above test confirms that the student object was injected correctly using StudentFactorygetObject() method.

Accessing FactoryBean instance:

We can inject the factoryBean instance using by adding “&” before the bean name.

Testing Student object injection using factoryBean injection:

@RunWith(SpringJUnit4ClassRunner.class

@ContextConfiguration(locations = { "classpath:spring-factory-beans.xml" }) 

publicclassStudentFactoryBeanXmlTest {        

                             @Resource(name="&student")                                                                                               privateStudentFactorystudentFactory;                 

                             @Test

publicvoidtestConstructWorkerByXml() throws Exception { assertThat(studentFactory.getObject().getEmail(), equalTo("test@gmail.com"));    

                 } 

}

 

Creating Factory Beans using Java Annotations:

We can create a configuration class using @Configuration annotation, and we can specify the class in @ContextConfiguration using the classes attribute.

Creating configuration class:

@Configuration 

publicclassStudentBeanConfig {       

                       @Bean(name="student")                                                                                                       publicStudentFactorygetStudentFactory()       

                      {              

                                             StudentFactorystudentFactory = newStudentFactory();              

                                            studentFactory.setEmail("test@gmail.com");                                                                          returnstudentFactory;       

                   }

}

And test class for Java annotation style:

@RunWith(SpringJUnit4ClassRunner.class

@ContextConfiguration(classes = StudentBeanConfig.class

publicclassStudentFactoryJavaTest {       

                  @Autowired       

                  private Student student;        

                  @Test       

                  publicvoidtestConstructWorkerByXml() {                                                                                                       assertThat(student.getEmail(), equalTo("test@gmail.com"));                  } 

}

Read More: What to Keep In Mind When Hiring Java Developers and Outsourcing Services?

The above test confirms that the Student object was injected correctly.

We can also inject the factoryBean instance using Java Annotation style similar to XML configuration.

@RunWith(SpringJUnit4ClassRunner.class

@ContextConfiguration(classes=StudentBeanConfig.class

publicclassStudentFactoryBeanJavaTest {          

                   @Resource(name="&student")                                                                                               privateStudentFactorystudentFactory;               

                  @Test

publicvoidtestConstructWorkerByXml() throws Exception {

                             assertThat(studentFactory.getObject().getEmail(), equalTo("test@gmail.com"));    

            } 

}

The above confirms that studentFactory Bean injecting successfully using “&” before the bean name.

Sometimes we need to do some operations before calling the getObject() method then we can use the InitializingBean interface, and implement the afterPropertiesSet() method or we can use @PostConstruct annotation on the operation implemented method so that it will be called on start-up.

Conclusion: we can use factoryBean for the complex scenarios for creating bean instances, we can either use xml configuration or annotation style. If the bean is of the type factoryBean then the spring IOC Container will call getObject() method on the instance for creating bean instances.

We can implement Initializing Bean interface or @PostConstruct annotation if we want to do some operations before calling the getObject() method to return the bean instance. FactoryBean also supports singleton and factory bean scoped bean instances.

You can follow the instructions shared by java outsourcing company experts here in this post and know the Factory Beans. If you have any questions, you may write in comments and wait for experts to respond to you.