Spring Create Bean Programatically

0

In this article we see how to create a bean programatically and register it. We may need this kind of dynamic bean creation if we want to conditionally create a bean based on certain information. For example, if oracle database, we want to create UCP (Oracle universal connection pool) datasource based on class oracle.ucp.jdbc.PoolDataSourceFactory else for all other databases based on tomcat datasource org.apache.tomcat.jdbc.pool.DataSource.

Let’s first look into our application context XML.

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:util="http://www.springframework.org/schema/util"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">

	<bean class="com.javarticles.jdbc.DbSettingsPostProcessor">
		<constructor-arg index="0" ref="dbProperties"/>
	</bean>	
	<util:properties id="dbProperties" location="classpath:/database.properties"/>
	<jdbc:initialize-database data-source="dataSource"
		enabled="true">
		<jdbc:script location="classpath:db-schema.sql" />
		<jdbc:script location="classpath:db-test-data.sql" />
	</jdbc:initialize-database>

</beans>

We want to initialize database, create table and insert some data into it. jdbc:initialize-database initializes the database. It relies on dataSource bean to execute scripts db-schema.sql and db-test-data.sql.

db-schema.sql:

drop table if exists `employee`;
CREATE TABLE `employee` (
  `ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(100) NOT NULL,
  `AGE` INT(3),
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

db-test-data.sql:

insert into employee(id, name) values (1, "Sam");
insert into employee(id, name) values (2, "John");

Implement BeanDefinitionRegistryPostProcessor to register bean

DbSettingsPostProcessor is the bean that registers the datasource bean dynamically based on the database type. It implements BeanDefinitionRegistryPostProcessor.
The database properties are passed to it in the constructor. In postProcessBeanDefinitionRegistry(), if database type is Oracle, we create a bean based on class name oracle.ucp.jdbc.PoolDataSourceFactory else for all other databases the bean class name would beĀ org.apache.tomcat.jdbc.pool.DataSource.

package com.javarticles.jdbc;

import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class DbSettingsPostProcessor implements
        BeanDefinitionRegistryPostProcessor {
    private Properties dbSettings;
    
    public DbSettingsPostProcessor(Properties dbSettings) {
        this.dbSettings = dbSettings;
    }

    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }

    public void postProcessBeanDefinitionRegistry(
            BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setLazyInit(true);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        beanDefinition.setPropertyValues(propertyValues);
        registry.registerBeanDefinition("dataSource", beanDefinition);
        
        if ("Oracle".equals(dbSettings.getProperty("dbType"))) {
            beanDefinition.setBeanClassName("oracle.ucp.jdbc.PoolDataSourceFactory");
            propertyValues.addPropertyValue("URL", dbSettings.getProperty("url"));
            propertyValues.addPropertyValue("connectionFactoryClassName", dbSettings.getProperty("driver"));
            propertyValues.addPropertyValue("connectionPoolName", "MyConnectionPool");
            propertyValues.addPropertyValue("user", dbSettings.getProperty("user"));
            propertyValues.addPropertyValue("password", dbSettings.getProperty("password"));
            if (dbSettings.containsKey("connectionWaitTimeout")) {
                propertyValues.addPropertyValue("connectionWaitTimeout", dbSettings.getProperty("connectionWaitTimeout"));
            }
            if (dbSettings.containsKey("inactiveConnectionTimeout")) {
                propertyValues.addPropertyValue("inactiveConnectionTimeout", dbSettings.getProperty("inactiveConnectionTimeout"));
            }
            if (dbSettings.containsKey("maxStatements")) {
                propertyValues.addPropertyValue("maxStatements", dbSettings.getProperty("maxStatements"));
            }
            if (dbSettings.containsKey("minPoolSize")) {
                propertyValues.addPropertyValue("minPoolSize", dbSettings.getProperty("minPoolSize"));
            }
            if (dbSettings.containsKey("maxPoolSize")) {
                propertyValues.addPropertyValue("maxPoolSize", dbSettings.getProperty("maxPoolSize"));
            }
            if (dbSettings.containsKey("initialPoolSize")) {
                propertyValues.addPropertyValue("initialPoolSize", dbSettings.getProperty("initialPoolSize"));
            }
            if (dbSettings.containsKey("validateConnectionOnBorrow")) {
                propertyValues.addPropertyValue("validateConnectionOnBorrow", dbSettings.getProperty("validateConnectionOnBorrow"));
            }
            if (dbSettings.containsKey("sqlForValidateConnection")) {
                propertyValues.addPropertyValue("sqlForValidateConnection", dbSettings.getProperty("sqlForValidateConnection"));
            }
        } else {
            beanDefinition.setBeanClassName("org.apache.tomcat.jdbc.pool.DataSource");
            propertyValues.addPropertyValue("url", dbSettings.getProperty("url"));
            propertyValues.addPropertyValue("driverClassName", dbSettings.getProperty("driver"));
            propertyValues.addPropertyValue("username", dbSettings.getProperty("user"));
            propertyValues.addPropertyValue("password", dbSettings.getProperty("password"));
            if (dbSettings.containsKey("testOnBorrow")) {
                propertyValues.addPropertyValue("testOnBorrow", dbSettings.getProperty("testOnBurrow"));
            }
            if (dbSettings.containsKey("maxActive")) {
                propertyValues.addPropertyValue("maxActive", dbSettings.getProperty("maxActive"));                
            }
            if (dbSettings.containsKey("maxWait")) {
                propertyValues.addPropertyValue("maxWait", dbSettings.getProperty("maxWait"));
            }
            if (dbSettings.containsKey("maxIdle")) {
                propertyValues.addPropertyValue("maxIdle", dbSettings.getProperty("maxIdle"));
            }
            if (dbSettings.containsKey("minIdle")) {
                propertyValues.addPropertyValue("minIdle", dbSettings.getProperty("minIdle"));
            }
            if (dbSettings.containsKey("initialSize")) {
                propertyValues.addPropertyValue("initialSize", dbSettings.getProperty("initializeSize"));
            }
            if (dbSettings.containsKey("sqlForValidateConnection")) {
                propertyValues.addPropertyValue("validationQuery", dbSettings.getProperty("sqlForValidateConnection"));
            }
        }
        
    }

}

database.properties:

dbType=MySQL
dataSourceClassName=org.apache.tomcat.jdbc.pool.DataSourceFactory
url=jdbc:mysql://localhost/test
driver=com.mysql.jdbc.Driver
user=root
password=admin
testOnBurrow=true
maxActive=25
maxWait=12000
maxIdle=10
initializeSize=6
sqlForValidateConnection=select 1

Let’s run the example.

SpringDynamicBeanCreationExample:

package com.javarticles.jdbc;

import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

public class SpringDynamicBeanCreationExample {
    public static void main(String[] args) throws SQLException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource datasource = (DataSource) context.getBean("dataSource");
        JdbcTemplate jdbcTemplate = new JdbcTemplate(datasource);
        List empList = jdbcTemplate.queryForList("select * from employee");
        System.out.println("Size of employees: " + empList.size());
    }
}

Output:

Apr 06, 2017 3:28:05 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org[email protected]179d3b25: startup date [Thu Apr 06 15:28:05 IST 2017]; root of context hierarchy
Apr 06, 2017 3:28:05 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
Apr 06, 2017 3:28:05 PM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [database.properties]
Apr 06, 2017 3:28:05 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.s[email protected]34b7bfc0: defining beans [com.javarticles.jdbc.DbSettingsPostProcessor#0,dbProperties,org.springframework.jdbc.datasource.init.DataSourceInitializer#0,dataSource]; root of factory hierarchy
Apr 06, 2017 3:28:05 PM org.springframework.jdbc.datasource.init.ResourceDatabasePopulator executeSqlScript
INFO: Executing SQL script from class path resource [db-schema.sql]
Apr 06, 2017 3:28:06 PM org.springframework.jdbc.datasource.init.ResourceDatabasePopulator executeSqlScript
INFO: Done executing SQL script from class path resource [db-schema.sql] in 115 ms.
Apr 06, 2017 3:28:06 PM org.springframework.jdbc.datasource.init.ResourceDatabasePopulator executeSqlScript
INFO: Executing SQL script from class path resource [db-test-data.sql]
Apr 06, 2017 3:28:06 PM org.springframework.jdbc.datasource.init.ResourceDatabasePopulator executeSqlScript
INFO: Done executing SQL script from class path resource [db-test-data.sql] in 8 ms.
Size of employees: 2

Download the source code

This was an example about creating a bean programatically and registering it in spring during runtime.

You can download the source code here: springDynamicBeanCreation.zip

About Author

Ram's expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring. You can reach him at [email protected]

Comments are closed.