Sunday, February 9, 2014

Spring çatısında Profile kullanımı

Spring 3.1 ile gelen yeniliklerden biri, değişik ortamlar için farklı ayarlar kullanmamıza olanak sağlayan profil tanımlamasıdır. Yazılım bir dizi etkinlik sonucu ortaya çıkar. Yazılım yaşam döngüsü olarak adlandırılan bu süreçte, yazılımın farklı ortamlarda çalıştırılır: geliştirme ortamı, test ortamı, üretim ortamı. Bu farklı ortamların ayarlarını her bir ortam için geliştirdiğimiz profillerde tanımlıyoruz. Profilleri Spring çatısının XML tabanlı yapılandırma dosyasında tanımlayabileceğimiz gibi @Profile damgasını kullanarak Java tabanlı olarak da tanımlayabiliriz.

1. XML tabanlı yapılandırma dosyasında profil tanımlama

spring-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
 <beans profile="prod">
  <context:component-scan base-package="com.example.service" />
  <context:component-scan base-package="com.example.dao">
    <context:exclude-filter type="regex" expression=".*InMemory.*"/>
  </context:component-scan>
  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource" />
  </bean>
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver" />
   <property name="url" value="jdbc:mysql://localhost:3306/customerdb" />
   <property name="username" value="root" />
   <property name="password" value="root" />
  </bean>
 </beans>
 <beans profile="dev">
  <context:annotation-config />
  <context:component-scan base-package="com.example.service" />
  <context:component-scan base-package="com.example.dao">
    <context:exclude-filter type="regex" expression=".*Jdbc.*"/>  
  </context:component-scan>
  <bean id="123456789101" class="com.example.domain.Customer">
   <property name="firstName" value="Jack" />
   <property name="lastName" value="Shephard" />
   <property name="identityNo" value="123456789101" />
  </bean>
  <bean id="109876543210" class="com.example.domain.Customer">
   <property name="firstName" value="Kate" />
   <property name="lastName" value="Austen" />
   <property name="identityNo" value="109876543210" />
  </bean>
 </beans>
</beans>

com.example.domain.Customer.java:
package com.example.domain;

public class Customer {
 private String firstName;
 private String lastName;
 private String identityNo;

 public Customer() {
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public String getIdentityNo() {
  return identityNo;
 }

 public void setIdentityNo(String identityNo) {
  this.identityNo = identityNo;
 }

 @Override
 public String toString() {
  return "Customer [firstName=" + firstName + ", lastName=" + lastName
    + ", identityNo=" + identityNo + "]";
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result
    + ((identityNo == null) ? 0 : identityNo.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Customer other = (Customer) obj;
  if (identityNo == null) {
   if (other.identityNo != null)
    return false;
  } else if (!identityNo.equals(other.identityNo))
   return false;
  return true;
 }
}

com.example.dao.CustomerDao.java:
package com.example.dao;

import com.example.domain.Customer;

public interface CustomerDao {
 void addCustomer(Customer customer);
 void deleteCustomer(String id);
 void updateCustomer(Customer customer);
 Customer findCustomerById(String id);
}

com.example.dao.CustomerInMemoryDao.java:
package com.example.dao;

import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
import com.example.domain.Customer;

@Repository("custdao")
@Profile("dev")
public class CustomerInMemoryDao implements CustomerDao {
 @Autowired
 private Map<String, Customer> customers;

 public CustomerInMemoryDao() {
 }

 public void setCustomers(Map<String, Customer> customers) {
  this.customers = customers;
 }

 public void addCustomer(Customer customer) {
  customers.put(customer.getIdentityNo(), customer);
 }

 public void deleteCustomer(String id) {
  customers.remove(id);
 }

 public void updateCustomer(Customer customer) {
  if (customers.containsKey(customer.getIdentityNo())) {
   customers.put(customer.getIdentityNo(), customer);
  }
 }

 public Customer findCustomerById(String id) {
  return customers.get(id);
 }
}

com.example.dao.CustomerJdbcDao.java:
package com.example.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.domain.Customer;

@Repository("custdao")
@Profile("prod")
public class CustomerJdbcDao implements CustomerDao {
 private static final String SQL_INSERT_CUSTOMER = "INSERT INTO CUSTOMERS(IDENTITYNO,FIRSTNAME,LASTNAME) VALUES ( ? , ? , ?)";
 private static final String SQL_SELECT_CUSTOMER_BY_ID = "SELECT * FROM CUSTOMERS WHERE IDENTITYNO=?";
 private static final String SQL_DELETE_CUSTOMER_BY_ID = "DELETE FROM CUSTOMERS WHERE IDENTITYNO=?";
 private static final String SQL_UPDATE_CUSTOMER_BY_ID = "UPDATE CUSTOMERS SET FIRSTNAME = ? , LASTNAME = ? WHERE IDENTITYNO = ?";

 @Autowired
 private JdbcTemplate jdbcTemplate;

 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
  this.jdbcTemplate = jdbcTemplate;
 }

 public CustomerJdbcDao() {
 }

 @Override
 public void addCustomer(Customer customer) {
  jdbcTemplate.update(
    SQL_INSERT_CUSTOMER,
    new Object[] { customer.getIdentityNo(),
      customer.getFirstName(), customer.getLastName() });
 }

 @Override
 public void deleteCustomer(String id) {
  jdbcTemplate.update(SQL_DELETE_CUSTOMER_BY_ID, new Object[] { id });
 }

 @Override
 public void updateCustomer(Customer customer) {
  jdbcTemplate.update(SQL_UPDATE_CUSTOMER_BY_ID,
    new Object[] { customer.getFirstName(), customer.getLastName(),
      customer.getIdentityNo() });
 }

 @Override
 public Customer findCustomerById(String id) {
  return jdbcTemplate.queryForObject(SQL_SELECT_CUSTOMER_BY_ID,
    new Object[] { id }, new BeanPropertyRowMapper<Customer>(
      Customer.class));
 }
}

com.example.TestXmlConfigProfileApp.java:
package com.example;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.dao.CustomerDao;
import com.example.domain.Customer;

public class TestXmlConfigProfileApp {
 public static void main(String[] args) {
  System.setProperty("spring.profiles.active", "prod");
  ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
    "spring-config.xml");
  CustomerDao custDao = (CustomerDao) context.getBean("custdao");
  Customer jack = custDao.findCustomerById("123456789101");
  System.out.println(jack);
  Customer kate = custDao.findCustomerById("109876543210");
  System.out.println(kate);
  context.close();
 }
}

Uygulamayı "prod" profilinde çalıştırdığımızda oluşan ekran görüntüsü aşağıda verilmiştir:
Feb 09, 2014 3:10:12 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2ef7d41f: startup date [Sun Feb 09 03:10:12 EET 2014]; root of context hierarchy
Feb 09, 2014 3:10:12 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Feb 09, 2014 3:10:13 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@49ea903c: defining beans [customerSrv,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,custdao,jdbcTemplate,dataSource,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Customer [firstName=Jin, lastName=Kwon, identityNo=123456789101]
Customer [firstName=Sun, lastName=Kwon, identityNo=109876543210]
Feb 09, 2014 3:10:13 AM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@2ef7d41f: startup date [Sun Feb 09 03:10:12 EET 2014]; root of context hierarchy
Feb 09, 2014 3:10:13 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@49ea903c: defining beans [customerSrv,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,custdao,jdbcTemplate,dataSource,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

Uygulamayı "dev" profilinde çalıştırdığımızda oluşan ekran görüntüsü aşağıda verilmiştir:
Feb 09, 2014 3:14:41 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2ef7d41f: startup date [Sun Feb 09 03:14:40 EET 2014]; root of context hierarchy
Feb 09, 2014 3:14:41 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Feb 09, 2014 3:14:41 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6cf49909: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,customerSrv,custdao,123456789101,109876543210,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Customer [firstName=Jack, lastName=Shephard, identityNo=123456789101]
Customer [firstName=Kate, lastName=Austen, identityNo=109876543210]
Feb 09, 2014 3:14:42 AM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@2ef7d41f: startup date [Sun Feb 09 03:14:40 EET 2014]; root of context hierarchy
Feb 09, 2014 3:14:42 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6cf49909: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,customerSrv,custdao,123456789101,109876543210,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

2. @Profile damgasını kullanarak Java tabanlı profil tanımlama

com.example.AppConfig.java:
package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile({"prod","dev"})
@Import(value = { AppConfigDev.class, AppConfigProd.class })
public class AppConfig {
}

com.example.config.AppConfigDev.java:
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.example.domain.Customer;

@Configuration
@Profile("dev")
@ComponentScan({ "com.example.service", "com.example.dao" })
public class AppConfigDev {
 @Bean(name = "123456789101")
 public Customer customer1() {
  Customer cust = new Customer();
  cust.setFirstName("Jack");
  cust.setLastName("Shephard");
  cust.setIdentityNo("123456789101");
  return cust;
 }

 @Bean(name = "109876543210")
 public Customer customer2() {
  Customer cust = new Customer();
  cust.setFirstName("Kate");
  cust.setLastName("Austen");
  cust.setIdentityNo("109876543210");
  return cust;
 }
}

com.example.config.AppConfigProd.java:
package com.example.config;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
@Profile("prod")
@ComponentScan({ "com.example.service", "com.example.dao" })
public class AppConfigProd {
 @Bean
 public JdbcTemplate jdbcTemplate() {
  BasicDataSource dataSource = new BasicDataSource();
  dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  dataSource.setUrl("jdbc:mysql://localhost:3306/customerdb");
  dataSource.setUsername("root");
  dataSource.setPassword("root");
  return new JdbcTemplate(dataSource);
 }
}

com.example.TestAppConfig.java:
package com.example;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.config.AppConfig;
import com.example.dao.CustomerDao;
import com.example.domain.Customer;

public class TestAppConfig {

 public static void main(String[] args) {
  ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
  context.getEnvironment().setActiveProfiles("prod");
  ((AnnotationConfigApplicationContext) context)
    .register(AppConfig.class);
  context.refresh();
  CustomerDao custDao = (CustomerDao) context.getBean("custdao");
  Customer jack = custDao.findCustomerById("123456789101");
  System.out.println(jack);
  Customer kate = custDao.findCustomerById("109876543210");
  System.out.println(kate);
  context.close();
 }
}

Uygulamayı "dev" profilinde çalıştırdığımızda oluşan ekran görüntüsü aşağıda verilmiştir:
Feb 09, 2014 3:47:57 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@8bfaf9f: startup date [Sun Feb 09 03:47:57 EET 2014]; root of context hierarchy
Feb 09, 2014 3:47:58 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3843d287: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,customerSrv,custdao,com.example.config.AppConfigDev,109876543210,123456789101]; root of factory hierarchy
Customer [firstName=Jack, lastName=Shephard, identityNo=123456789101]
Customer [firstName=Kate, lastName=Austen, identityNo=109876543210]
Feb 09, 2014 3:47:58 AM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@8bfaf9f: startup date [Sun Feb 09 03:47:57 EET 2014]; root of context hierarchy
Feb 09, 2014 3:47:58 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3843d287: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,customerSrv,custdao,com.example.config.AppConfigDev,109876543210,123456789101]; root of factory hierarchy

Uygulamayı "prod" profilinde çalıştırdığımızda oluşan ekran görüntüsü aşağıda verilmiştir:
Feb 09, 2014 3:50:05 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@60a2f435: startup date [Sun Feb 09 03:50:05 EET 2014]; root of context hierarchy
Feb 09, 2014 3:50:06 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6cb2b9ec: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,customerSrv,custdao,com.example.config.AppConfigProd,jdbcTemplate]; root of factory hierarchy
Customer [firstName=Jin, lastName=Kwon, identityNo=123456789101]
Customer [firstName=Sun, lastName=Kwon, identityNo=109876543210]
Feb 09, 2014 3:50:07 AM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@60a2f435: startup date [Sun Feb 09 03:50:05 EET 2014]; root of context hierarchy
Feb 09, 2014 3:50:07 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6cb2b9ec: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,customerSrv,custdao,com.example.config.AppConfigProd,jdbcTemplate]; root of factory hierarchy

Projeyi maven projesi olarak bu adresten indirebilirsiniz.

No comments:

Post a Comment