2019년 6월 13일

스프링에서 동적으로 빈 등록하여 사용하기

스프링 프레임워크에서 빈을 등록하는 방법으로 XML 이나 Classpath 검색 기반의 어노테이션을 사용하고 있다. 웹 프로그램에서 설정 정보에 따라 동적으로 Bean을 추가하려면 AutowireCapableBeanFactory 를 사용하면 쉽게 구현이 가능하다.  

예를 들어 데이터베이스 접속을 위한 DataSource 를 동적으로 추가한다고 해보자 . 


 
package tests;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Component;

@Component
public class SetupService implements ApplicationContextAware {

 private static final Logger logger = LoggerFactory.getLogger(SetupService.class);

 private ApplicationContext applicationContext = null;
 
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = applicationContext;
 }
 
 public SetupService() { 
 }
 
 public boolean testConnection(DataSource dataSource) { 
  try {
   JdbcUtils.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() { 
    public Object processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException { 
     logger.debug( "Database Connection Test  : {}" , true );
     logger.debug( "Database Product Name : {}" , dbmd.getDatabaseProductName() );
     logger.debug( "Database Product Version : {} " , dbmd.getDatabaseProductVersion() );
     logger.debug( "JDBC DriverName : {} " , dbmd.getDriverName() );
     logger.debug( "JDBC Driver Version : {} " , dbmd.getDriverVersion());
     return dbmd;
    } 
   }); 
   return true;
  } catch (Exception e) {
   logger.error(e.getMessage(), e);
  }
  return false;
 }
 
 public  T getComponent(String requiredName, Class requiredClass) { 
  return applicationContext.getBean(requiredName, requiredClass);
 }
 
 public void registerDataSourceBean(String name, Properties connectionProperties) {

  AutowireCapableBeanFactory factory =  applicationContext.getAutowireCapableBeanFactory();
  BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory; 
  if(registry.containsBeanDefinition(name)) {
   registry.removeBeanDefinition(name);
  } 
  GenericBeanDefinition myBeanDefinition = new GenericBeanDefinition();
  
  MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
  mutablePropertyValues.add("url", connectionProperties.getProperty("url"));
  mutablePropertyValues.add("username", connectionProperties.getProperty("username"));
  mutablePropertyValues.add("password", connectionProperties.getProperty("password"));
  mutablePropertyValues.add("connectionProperties", connectionProperties);
  
  myBeanDefinition.setBeanClass(DriverManagerDataSource.class);
  myBeanDefinition.setPropertyValues(mutablePropertyValues);
  registry.registerBeanDefinition(name, myBeanDefinition); 
 }

}

다음과 같이 위의 컴포넌트를 사용하여 동적으로 DataSource 를 추가하여 사용할 수 있다.
 
Properties connectionProperties = new Properties();
connectionProperties.setProperty("DriverClassName", "oracle.jdbc.OracleDriver");
connectionProperties.setProperty("url", "jdbc:oracle:thin:@//localhost:1521/orcl");
connectionProperties.setProperty("username", "**" );
connectionProperties.setProperty("password", "**");   
setupService.registerDataSourceBean("dataSource", connectionProperties);
DataSource dataSource = setupService.getComponent("dataSource", DataSource.class);
setupService.testConnection(dataSource);

환경 

Java : 1.8.x
Springframework : 4.3.23.RELEASE

참고 

https://stackoverflow.com/questions/43051394/how-to-add-bean-instance-at-runtime-in-spring-webapplicationcontext

댓글 없음:

댓글 쓰기