Back Ground

Environment , 프로퍼티 , 프로필 , 메시지 본문

Spring

Environment , 프로퍼티 , 프로필 , 메시지

Back 2016. 11. 19. 18:36

Environment 인바이어런먼트


외부에서 입력한 정보를 이용해서 

설정값을 변경하는 방법들을 제공하고 있는 방법


ex) 톰켓 서버에 server.xml 이라는 파일에 사용할 포트번호를 설정하며,

    아파치 웹 서버는 httpd.conf 파일에 포트 번호와 디렉토리 경로를 설정한다. 



Environment는 두가지 기능 제공

 - 프로퍼티 통합관리

 - 프로필을 이용해서 선택적으로 설정 정보를 사용할 수 있는 방법 제공


Environment는

  시스템 환경변수 , JVM 시스템 프로퍼티 , 프로퍼티 파일 등의 프로퍼티를 

  PropertySource라는 것으로 통홥관리한다.

@PropertySource ( "classpath : /com/myco/app.properties") 클래스 경로 :

따라서 설정 파일이나 클래스 수정없이 시스템 프로퍼티나 프로퍼티 파일 등을 이용해서 설정 정보의 일부를 변경 할 수 있다.



Environment는 스프링 프레임워크 (Spring Framework)가 자동으로 Inject하는 빈 (Bean)이다. 

@PropertySource로 Property 파일을 Environment로 로딩할 수 있다


프로퍼티 사용법





-예제-
SpringSocial/src/main/resources/setting.properties 파일 내용이 다음과 같다고 하자. 

#facebook appId, secretKey 
facebook.appId=575657749192479 
facebook.secretKey=df3ebe71b7eee8771c6fee1e0124f9ec 
callback.host=http://localhost:8080 


-SocialController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.home.social;
 
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.FacebookLink;
 
@Controller
@RequestMapping("/facebook")
@PropertySource("classpath:/setting.properties")
public class SocialController {
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
         
    @Resource
    private Environment environment;
         
    @RequestMapping(value="/getFriendInfo")
    public String getFriendsInfo(HttpSession session, Model model){
        Facebook facebook = new FacebookTemplate((String)session.getAttribute("ACCESS_TOKEN"));
        List<string> friends = facebook.friendOperations().getFriendIds();
                 
        logger.info("facebook.appId: " + environment.getProperty("facebook.appId"));
        logger.info("facebook.secretKey:" + environment.getProperty("facebook.secretKey"));
         
        model.addAttribute("friendsList", friends);
        return "index";
    }
}
</string>
cs
실행 결과는 다음과 같다. 
facebook.appId: 575657749192479 
facebook.secretKey: df3ebe71b7eee8771c6fee1e0124f9ec



또한 Environment는 

- 여러 프로필(profile)중에서 특정 프로필을 활성화하는 기능을 제공 해주는데  

  이 기능을 사용하면 개발 환경, 통합 테스트 환경, 실 서비스 환경에 따라서로 다른 스프링 빈 설정을 선택할 수 있기 때문에,

  서로 다른 환경을 위한 설정 정보를 편리하게 관리할 수 있다.

  






Environment 구하기


o.s.core.env.Environment를 직접 사용할 일이 많지않지만, 

코드에서 프로필을 선택하거나

Environment에 새로운 PropertySource를 직접 추가해주야 한다면 

ConfigurableApplicationContext에 정의getEnvironment()메서드를 이용해서 Environment를 구할 수 있다.


1
2
3
4
5
  import org.springframework.core.env.ConfigurableEnvironment;
  ...
  ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
  ConfiguralbeEnvironment environment = context.getEnvironment();
  environment.setActiveProfiles("dev");
cs


getEnvironment()메서드리턴하는 타입은 

Environment의 하위 타입인 

o.s.core.env.ConfigurableEnvironment 타입이다. 

ConfigfurableEnvironment 타입은 사용할 프로필을 선택하는 기능PropertySource를 추가하는데 필요한 기능을 제공한다.



Spring 3.1 에서 부터 

"Environment" interface를 추가했다. 

Environment는 ApplicationContext 에서 getEnvironment() 메소드를 통해 이러한 접근할 수 있는데, 

이 Environment (구체적으로 ConfigurableEnvironment)는 아래 세가지 기능을 지원합니다.


- Profile 에 대한 선택 (active profile)

- Property 에 대한 통합된 접근 제공

- Conversion 서비스에 대한 접근 제공



출처 : http://sinihong.tistory.com/57



Environment 기능

프로퍼티 값을 제공하는 기능

스프링컨테이너가 기본으로 사용하는 Environmnet의 구현체는 다수의 propertySource로 부터 프로퍼티 값을 읽어온다.



Environment의 프로퍼티를 읽어 오는 과정


 

 

 ↓

1. 프로퍼티 값 요청 

 

 

 

ConfigurableEnvironment

 

 

 

 

  ↓

2. 프로퍼티 값 요청 

 

 

 

MutablePropertySources 

 

 

 

 

 | 

 

 

┌ 

┴ 

 ┐

↓ 

 

↓ 

↓ 

 시스템프로퍼티

PropertySource

환경 변수

PropertySource 

 

자바 Properties

PropertySource 

JNDI

PropertySource 




o.s.core.env.MutablePropertySources에 두 개 이상의 PropertySource가 등록되어 있을 경우

프로퍼티 값을 구할 때까지 등록된 순서에 따라 차례대로 확인한다.


ex)예를 들어 이름이 JAVA_HOME인 환경변수가 존재하고 

위 표에서  PropertySource의 우선순위왼쪽이 높고 오른쪽이 낮다가정해보자. 

이때 Environment로부터 "JAVA_HOME" 프로퍼티의 값을 구하면, 먼저 시스템 프로퍼티 PropertySource로 부터 프로퍼티 값을 찾는다.

시스템프로퍼티에는 "JAVA_HOME" 프로퍼티가 존재하지 않으므로, 두번째 PropertySource를 확인한다.

두번째 PropertySource는  환경 변수로부터 값을 읽어오므로 

환경 변수인 JAVA_HOM에 담긴 값을 "JAVA_HOME" 프로퍼티의 값으로 리턴하며,

Environmenrt는 이 값을 사용하게 된다. 



properties


db.properties

1
2
3
4
db.driver=com.mysql.Driver
db.jdbcUrl=jdbc:mysql://host/test
db.user=madvirus
db.password=bkchoi
cs



JAVA 방식

예제


MainByEnvOfJava.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package net.madvirus.spring4.chap04;
 
import java.io.IOException;
 
import net.madvirus.spring4.chap04.config.ConfigByEnv;
 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
 
public class MainByEnvOfJava {
 
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
 
        ctx.register(ConfigByEnv.class);
        ctx.refresh();
 
        ConfigurableEnvironment env = ctx.getEnvironment();
        String javaVersion = env.getProperty("java.version");
        String dbUser = env.getProperty("db.user");
        System.out.printf("java version is %s\n", javaVersion);
        System.out.printf("dbUser is %s\n", dbUser);
 
        ctx.close();
    }
}
 
cs


ConfigByEnv.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package net.madvirus.spring4.chap04.config;
 
import net.madvirus.spring4.chap04.ConnectionProvider;
import net.madvirus.spring4.chap04.JdbcConnectionProvider;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;
 
@Configuration
@PropertySources(@PropertySource("classpath:/db.properties"))
public class ConfigByEnv {
 
    @Autowired
    private Environment env;
 
    @Bean(initMethod = "init")
    public ConnectionProvider connectionProvider() {
        JdbcConnectionProvider connectionProvider = new JdbcConnectionProvider();
        connectionProvider.setDriver(env.getProperty("db.driver"));
        connectionProvider.setUrl(env.getProperty("db.jdbcUrl"));
        connectionProvider.setUser(env.getProperty("db.user"));
        connectionProvider.setPassword(env.getProperty("db.password"));
        return connectionProvider;
    }
}
 
cs





XML 방식


MainByEnvOfXml.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package net.madvirus.spring4.chap04;
 
import java.io.IOException;
 
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.io.support.ResourcePropertySource;
 
public class MainByEnvOfXml {
 
    public static void main(String[] args) throws IOException {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ConfigurableEnvironment env = ctx.getEnvironment();
        MutablePropertySources propSources = env.getPropertySources();
        propSources.addLast(new ResourcePropertySource("classpath:/db.properties"));
 
        String javaVersion = env.getProperty("java.version");
        String dbUser = env.getProperty("db.user");
        System.out.printf("java version is %s\n", javaVersion);
        System.out.printf("dbUser is %s\n", dbUser);
    }
}
 
cs



db-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
 
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context
       http://www.springframework.org/schema/context/spring-context.xsd">
 
    <context:property-placeholder location="classpath:/db.properties, classpath:/app.properties" />
 
    <bean id="connProvider" class="net.madvirus.spring4.chap04.JdbcConnectionProvider"
        init-method="init">
        <property name="driver" value="${db.driver}" />
        <property name="url" value="${db.jdbcUrl}" />
        <property name="user" value="${db.user}" />
        <property name="password">
            <value>${db.password}</value>
        </property>
    </bean>
 
</beans>
 
 
cs

Profiles

 

 Maven의 profile 과 비슷한 기능이라고 이해하면 됩니다. 

 Maven의 profile 설정은 java application을 'build' 할 때 다른 설정을 적용할 수 있는 방법을 제공합니다. 

 예를 들어 development 환경과 production 환경의 database 접속 설정은 당연히 다를 것이고, 

 이 경우 development 와 production 용 두 개의 database 접속 설정을 만들어 놓고 build 시 profile 을 지정하여 해당 설정이 적용되도록 할 수 있습니다.













Message


<spring:masseage>



사용자 화면에 보여질 문자열은 JSP 코드에 직접 넣은것이 보통이다 .


1
2
<label>이메일</label>
<input type="text" name="email">
cs

이렇게 문자열을 직접 하드 코딩할때 문제점은 동일 문자열을 변경할 때 발생한다.

"이메일"과 같은 문자열은 로그인 폼, 회원가입 폼, 회원 정보수정 폼 등에서 반복해서 사용된다.


예를 들어 사용할 '이메일'을 '이메일 주소'로 변경하기로 했다면 각 폼을 출력하는 JSP를 찾아서 변경해주어야 한다.


문자열이 뷰 코드에 하드코딩되어 있을때의 또 다른 문제점은 다국어 지원이다.

전 세계 대상으로 서비스 하는 경우,  사용자의 언어 설정에 따라 '이메일' -> 'E-mail'과 같이 표시해줘야한다.



문자열을 별도 파일에 작성하고 JSP 코드에서 이를 사용하려면 

1. 메시지 파일을 작성한다.

2. 메시지 파일에서 값을 읽어오는 MessageSource빈을 설정한다

3. JSP 코드에서 <spring:message> 태그를 사용해서 메시지를 출력한다.(spring: = taglib 태그라이브러리)



먼저 메시지파일은 작성한다

메시지 파일은 자바의 프로퍼티 파일 형식으로 작성한다.  

메시지 파일을 보관하기 위해 ser/main/resources에 massage 폴더를 생성하고 이 폴더에 빈 label.properties 파일을 생성한다.




UTF-8 인코딩을 사용해서  lable.properties 파일을 작성하는데,

이를 위해 label.properties 파일을 열때

 

Text Editor를 사용해서 연다.

(Properties File Editor를 이용해서 열 경우) 

'이메일'과 같은 한글 문자가 다른 유니코드 값으로 표현되기 때문에 나중에 알아보기 힘들어진다.



(사용하기전 설정에서 UTF-8로 변경해준다)

메시지 파일을 작성했다면, 다음으로 MessageSource타입의 빈을 추가해준다.

스프링 설정 중 한곳에 추가해주면 되는데, 여기선 spring-mvc.xml 파일에 추가해 준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 
    <annotation-driven />
 
    <resources mapping="/resources/**" location="/resources/" />
 
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
    
    <context:component-scan base-package="com.spring.ex" />
    
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>message.label</value>
                  <!-- 패키지이름.파일 -->
            </list>
        </property>
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>
    
</beans:beans>
 
cs


basenames 프로퍼티의 값으로 "message.label"을 주었는데, 

이는 message패키지에 속한 label 프로퍼티 파일로부터 메세지를 읽어온다고 설정


즉, 이 설정은 앞서 작성한 label.properties 파일로부터 메시지를 읽어오게 된다. basenames프로퍼티는 리스트를 값으로 가지므로, 

여러 프로퍼티 파일을 사용하고 싶은 경우에는 다음과 같이 <list> 태그에 여러 개의 <value>를 설정해주면 된다.


그리고 label.properties 파일을 작성할 때 UTF-8 인코딩을 사용했으므로 defaultEncoding 속성의 값으로 "UTF-8"을 설정 했다.


위 코드에서 주의할 점 !


빈의 아이디를 "messageSource"로 지정해야 한다는 것!

다른 이름을 사용하는 경우 정상적으로 동작하지 않는다. 





jsp부분 사용법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
 
<!DOCTYPE html>
<html>
    <head>
        <title>메시지 예제</title>
    </head>
    <body>
        <p>
            <label><spring:message code="email"></label>
        </p>
    </body>
</html>
 
cs


<spring:message> 커스텀 태그를 사용하기 위한 태그 라이브러리 설정 추가

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>


<spring:message> 태그를 이용해서 메시지 출력


<spring:message code="email">  의 code값은 프로퍼티 파일의 이름과 일치하는 값을 사용한다.



출력할시 

<label> 부분에 '이메일' 이 출력 되는걸 확인할 수 있다




MessageSource


스프링은 메시지의 국제화를 지원하기 위해 o.s.context.MessageSource 인터페이스를 제공하고 있다.


스프링은 로케일(지역)에 상관없이 일관된 방법으로 문자열(메시지)을 관리할 수 있는 MessageSource 인터페이스를 정의하고있다.


MessageSource 인터페이스는 지역 및 언어에 따라 알맞은 메세지를 구할 수 있는 메서드가 다음과 같이 정의 되어 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.springframework.context;
 
import java.util.Locale;
 
public interface MessageSource{
    
    String getMessage(String code, Object[] args, String defaultMassage, Locale locale);
 
    String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
    
    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
 
}
cs

특정 로케일에 해당하는 메시지가 필요한 코드는 

MessageSource의 getMessage()메서드를 이용해서 필요한 메시지를 가져와서 사용하면된다.


getMessage()메서드의 code 파라미터는 메시지를 구분하기 위한 코드를,

 locale 파라미터는 지역 구분하기 위한 Locale을 값으로 받는다.

즉, 코드가 하나더라도 지역에 따라 다른 메시지를 제공할 수 있도록 MessageSource를 설계했다. 이 기능을 사용하면 국내에서

접근하면 '한국어' 메시지로 보여주고, 해외에서 접근하면 '영어'메시지로 보여주는 처리를 할 수 있다.


다시 말하자면 

각 getMessage() 메서드는 Locale에 따라 알맞은 메시지를 리턴한다.  

예를 들어 

Locale.KOREAN을 값으로 주면 한국어를 기준으로 읽어오며 

Locale.ENGLISH를 값으로 주면 영어를 기준으로 읽어온다.

해당 Locale에 맞는 메시지가 없는 경우 기본 메시지를 리턴한다.


ApplicationContext는 등록된 빈 객체 중에서 이름이 

'messageSource'인 MessageSource 타입의 빈 객체를 이용해서 메시지를 가져온다

따라서, ApplicationContext를 이용하여 메시지를 가져오려면, 


1
2
3
4
5
6
7
<bean id="messageSource" 
    class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>message.greeting</value>
        </property>
</bean>
cs

아까 말했듯 위와같이 스프링 파일 이름이 'messageSource'인 빈 객체를 정의 해주어야 한다. 

(빈 객체의 이름이"messageSource"가 아닌 경우 ApplicationContext를 이용한 메시지 읽기 기능이 옳바르게 동작하지 않는다.) 

'Spring' 카테고리의 다른 글

파일 다운로드 처리 (File Download)  (2) 2017.07.11
DI(의존성 주입)  (4) 2016.11.23
Spring EcoLibrary - Mybatis 순서  (0) 2016.10.12
Spring Framework: annotation 정리 #1  (0) 2016.09.22
Spring 컨테이너 및 설정 파일  (0) 2016.07.19
Comments