아무거나

[spring] 외부 파일을 이용한 설정 본문

Java & Kotlin/Spring

[spring] 외부 파일을 이용한 설정

전봉근 2019. 12. 25. 23:39
반응형

[spring] 외부 파일을 이용한 설정

 

1. Environment 객체

   - Environment객체를 이용해서 스프링 빈 설정을 한다.

     Context -> ( ctx.getEnvironment() ) -> Environment -> ( env.getPropertySources() ) -> PropertySources

 

     PropertySources : 프로퍼티 추가 및 추출

     추가 : propertySources.addLast()

     추출 : env.getProperty()

 

[MainClas.java]

public class MainClass {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new GenericXmlApplicationContext(); // context를 구한다.
        ConfigurableEnvironment env = ctx.getEnvironment(); // Environment 객체를 구한다.
        MutablePropertySources propertySources = env.getPropertySources(); // Environment가 데이터를 갖고있을때 getPropertySources를 이용하여 properties소스를 다 가져온다.

        try {
            // ResourcePropertySource 객체를 이용하여 외부설정파일인 classpath:admin.properties를 갖다가 객체를 만든다.
            // 추가 : propertySources.addLast()  -> 내가만든 환경설정을 뒤에 추가한다.
            propertySources.addLast(new ResourcePropertySource("classpath:admin.properties"));

            // 위의 classpath:admin.properties 을 가져온 애들을 출력한다.
            // 추출 : env.getProperty()
            System.out.println( env.getProperty("admin.id") );
            System.out.println( env.getProperty("admin.pw") );
        } catch (IOException e) {}

        GenericXmlApplicationContext gCtx = (GenericXmlApplicationContext)ctx; // 빈 생성
        gCtx.load("applicationCTX.xml"); // 컨테이너 설정
        gCtx.refresh(); // 빈 객체 생성

        // getBean에서 adminConnection을 구한다.
        // AdminConnection( EnvironmentAware : 빈이 생성되기 아주 처음에 생성된다. 즉, InitializingBean, DisposableBean 보다 더 빨리 된다. )
        AdminConnection adminConnection = gCtx.getBean("adminConnection", AdminConnection.class);
        System.out.println("admin ID : " + adminConnection.getAdminId());
        System.out.println("amdin PW : " + adminConnection.getAdminPw());

        gCtx.close();
        ctx.close();
    }
}

 

[AdminConnection.java]

public class AdminConnection implements EnvironmentAware, InitializingBean, DisposableBean {
    private Environment env;
    private String adminId;
    private String adminPw;

    @Override
    public void setEnvironment(Environment env) {
    	System.out.println("setEnvironment()");
    	setEnv(env);
    }

    public void setEnv(Environment env) {
    	this.env = env;
    }

    public void setAdminId(String adminId) {
    	this.adminId = adminId;
    }



    public void setAdminPw(String adminPw) {
    	this.adminPw = adminPw;
    }

    public String getAdminId() {
    	return adminId;
    }

    public String getAdminPw() {
    	return adminPw;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    	System.out.println("afterPropertiesSet()");
    	setAdminId(env.getProperty("admin.id"));
    	setAdminPw(env.getProperty("admin.pw"));
    }

    @Override
    public void destroy() throws Exception {
    	System.out.println("destroy()");
    }
}

 

[applicationCTX.xml]

<?xml version="1.0" encoding="UTF-8"?>
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">
<bean id="adminConnection" class="com.javalec.ex.AdminConnection" />
</beans>

 

[admin.properties]

admin.id=abcde
admin.pw=12345

 

 

 

2. 프로퍼티 파일을 이용한 설정 

   * Environment객체를 사용하지 않고 프로퍼티 파일을 직접 이용하여 스프링 빈을 설정한다.

 

   # 스프링 설정 XML파일에 프로퍼티 파일을 명시

     [MainClass.java]

public class MainClass {
    public static void main(String[] args) {
        AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
        AdminConnection connection = ctx.getBean("adminConnection", AdminConnection.class);
        System.out.println("adminID : " + connection.getAdminId());
        System.out.println("adminPW : " + connection.getAdminPw());
        System.out.println("sub_adminID : " + connection.getSub_adminId());
        System.out.println("sub_adminPW : " + connection.getSub_adminPw());
        ctx.close();
    }
}

 

     [applicationCTX.xml]

<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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-3.2.xsd">
<context:property-placeholder location="classpath:admin.properties, classpath:sub_admin.properties" />
<bean id="adminConnection" class="com.javalec.ex.AdminConnection" >
    <property name="adminId">
        <value>${admin.id}</value>
    </property>
    <property name="adminPw">
        <value>${admin.pw}</value>
    </property>
    <property name="sub_adminId">
        <value>${sub_admin.id}</value>
    </property>
    <property name="sub_adminPw">
        <value>${sub_admin.pw}</value>
    </property>
</bean>
</beans>

 

* xmlns:context와 xsi:schemaLocation에 context관련 내용이 추가되어야함. (namespaces에서 context 선택) --> 그래야 위에 context 태그에서 에러가 안생김

 

     [admin.properties]

admin.id=abcde
admin.pw=12345

 

     [sub_admin.properties]

sub_admin.id=fghij
sub_admin.pw=67890

 

     [AdminConnection.java]

public class AdminConnection implements InitializingBean, DisposableBean {
    private String adminId;
    private String adminPw;
    private String sub_adminId;
    private String sub_adminPw;

    public void setAdminId(String adminId) {
    	this.adminId = adminId;
    }

    public void setAdminPw(String adminPw) {
    	this.adminPw = adminPw;
    }

    public void setSub_adminId(String sub_adminId) {
    	this.sub_adminId = sub_adminId;
    }

    public void setSub_adminPw(String sub_adminPw) {
    	this.sub_adminPw = sub_adminPw;
    }

    public String getAdminId() {
    	return adminId;
    }

    public String getAdminPw() {
    	return adminPw;
    }

    public String getSub_adminId() {
    	return sub_adminId;
    }

    public String getSub_adminPw() {
    	return sub_adminPw;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    	System.out.println("afterPropertiesSet()");
    }

    @Override
    public void destroy() throws Exception {
    	System.out.println("destroy()");
    }

}

 

     [결과]

     afterPropertiesSet()

     adminID : abcde

     adminPW : 12345

     sub_adminID : fghij

     sub_adminPW : 67890

     destroy()

 

 

   # 스프링 설정 JAVA파일에 프로퍼티 파일을 명시

     [MainClass.java]

public class MainClass {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        AdminConnection connection = ctx.getBean("adminConfig", AdminConnection.class);

        System.out.println("adminID : " + connection.getAdminId());
        System.out.println("adminPW : " + connection.getAdminPw());
        System.out.println("sub_adminID : " + connection.getSub_adminId());
        System.out.println("sub_adminPW : " + connection.getSub_adminPw());

        ctx.close();
    }
}

 

     [ApplicationConfig.java]

@Configuration // config관련 어노테이션 선언
public class ApplicationConfig {
    // @Value를 사용하면 알아서 properties값이 필드에 매핑됨.
    @Value("${admin.id}")
    private String adminId;
    
    @Value("${admin.pw}")
    private String adminPw;

    @Value("${sub_admin.id}")
    private String sub_adminId;

    @Value("${sub_admin.pw}")
    private String sub_adminPw;

    // PropertySourcesPlaceholderConfigurer은 xml파일에서 <context:property-placeholder... 이다.
    // static이므로 메모리에 할당되서 Properties()메소드를 바로 쓸 수 있다.
    @Bean
    public static PropertySourcesPlaceholderConfigurer Properties() { 
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); // PropertySourcesPlaceholderConfigurer타입의 configurer 생성
        Resource[] locations = new Resource[2];  // Resource배옅 생성

        // properties 배열에 담고 위에 만든 configurer에 set을한다. 해당 파일의 path를 알려주고 그에 대한 값들을 return configurer로 반환한다.
        locations[0] = new ClassPathResource("admin.properties");
        locations[1] = new ClassPathResource("sub_admin.properties");
        configurer.setLocations(locations);

        return configurer;
    }

    @Bean
    public AdminConnection adminConfig() {
        // 위에 @Value로 선언된 값들을 setter을 이용해서 AdminConnection에 저장. 그리고 MainClass에서 getter로 가져오면 출력된다.
        AdminConnection adminConnection = new AdminConnection();
        adminConnection.setAdminId(adminId);
        adminConnection.setAdminPw(adminPw);
        adminConnection.setSub_adminId(sub_adminId);
        adminConnection.setSub_adminPw(sub_adminPw);
        return adminConnection;
    }
}

 

     [admin.properties]

admin.id=abcde
admin.pw=12345

 

     [sub_admin.properties]

sub_admin.id=fghij
sub_admin.pw=67890

 

     [applicationCTX.xml]

<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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-3.2.xsd">
<context:property-placeholder location="classpath:admin.properties, classpath:sub_admin.properties" />
<bean id="adminConnection" class="com.javalec.ex.AdminConnection" >
    <property name="adminId">
    	<value>${admin.id}</value>
    </property>
    <property name="adminPw">
    	<value>${admin.pw}</value>
    </property>
    <property name="sub_adminId">
    	<value>${sub_admin.id}</value>
    </property>
    <property name="sub_adminPw">
    	<value>${sub_admin.pw}</value>
    </property>
</bean>
</beans>

 

 

     [AdminConnection.java]

public class AdminConnection implements InitializingBean, DisposableBean {
    private String adminId;
    private String adminPw;
    private String sub_adminId;
    private String sub_adminPw;

    public void setAdminId(String adminId) {
    	this.adminId = adminId;
    }

    public void setAdminPw(String adminPw) {
    	this.adminPw = adminPw;
    }

    public void setSub_adminId(String sub_adminId) {
    	this.sub_adminId = sub_adminId;
    }

    public void setSub_adminPw(String sub_adminPw) {
    	this.sub_adminPw = sub_adminPw;
    }

    public String getAdminId() {
    	return adminId;
    }

    public String getAdminPw() {
    	return adminPw;
    }

    public String getSub_adminId() {
    	return sub_adminId;
    }

    public String getSub_adminPw() {
    	return sub_adminPw;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    	System.out.println("afterPropertiesSet()");
    }

    @Override
    public void destroy() throws Exception {
    	System.out.println("destroy()");
    }
}

 

3. 프로파일(profile) 속성을 이용한 설정

   * 동일한 스프링 빈을 여러 개 만들어 놓고 상황(ex:개발환경)에 따라 적절한 스프링 빈을 사요여할 수 있다.

     profile속성을 사용하자.

     

     [MainClass.java]

public class MainClass {
    public static void main(String[] args) {
        String config = null;
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        if(str.equals("dev")) {
        	config = "dev";
        } else if(str.equals("run")) {
        	config = "run";
        }

        scanner.close();
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); // xml설정파일 가져옴
        ctx.getEnvironment().setActiveProfiles(config); // 위에서 구한 config값에 따라서 아래 xml파일중에 하나를 이용
        ctx.load("applicationCTX_dev.xml", "applicationCTX_run.xml");

        ServerInfo info = ctx.getBean("serverInfo", ServerInfo.class); // getBean이용하여 객체를 가져옴
        System.out.println("ip : " + info.getIpNum());
        System.out.println("port : " + info.getPortNum());
        ctx.close();
    }
}

 

     [applicationCTX_dev.xml]

<?xml version="1.0" encoding="UTF-8"?>
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"
profile="dev">
<bean id="serverInfo" class="com.javalec.ex.ServerInfo">
	<property name="ipNum" value="localhost"></property>
	<property name="portNum" value="8181"></property>
</bean>
</beans>

 

* 위에 beans태그중 마지막에 profile="dev"로 설정하자. MainClass.java에 선언된 setActiveProfiles메소드로 해당 xml파일을 구분함

 

     [applicationCTX_run.xml]

<?xml version="1.0" encoding="UTF-8"?>
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"
profile="run">
<bean id="serverInfo" class="com.javalec.ex.ServerInfo">
    <property name="ipNum" value="222.222.223.29"></property>
    <property name="portNum" value="80"></property>
</bean>
</beans>

 

* 위에 beans태그중 마지막에 profile="run"로 설정하자. MainClass.java에 선언된 setActiveProfiles메소드로 해당 xml파일을 구분함

 

     [ServerInfo.java]

public class ServerInfo {
    private String ipNum;
    private String portNum;

    public String getIpNum() {
    	return ipNum;
    }

    public void setIpNum(String ipNum) {
    	this.ipNum = ipNum;
    }

    public String getPortNum() {
    	return portNum;
    }

    public void setPortNum(String portNum) {
    	this.portNum = portNum;
    }
}

 

    ### 위에 방법을 java로 이용하는 방법이 있다.(잘 쓰이지 않는 방법이다.)

    [MainClass.java]

public class MainClass {
    public static void main(String[] args) {
        String config = null;
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        if(str.equals("dev")) {
        	config = "dev";
        } else if(str.equals("run")) {
        	config = "run";
        }

        scanner.close();

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.getEnvironment().setActiveProfiles(config);
        ctx.register(ApplicationConfigDev.class, ApplicationConfigRun.class);
        ctx.refresh();

        ServerInfo info = ctx.getBean("serverInfo", ServerInfo.class);
        System.out.println("ip : " + info.getIpNum());
        System.out.println("port : " + info.getPortNum());
        ctx.close();
    }
}

 

[ApplicationConfigRun.java]  // or ApplicationConfigDev.java

@Configuration
@Profile("run")
public class ApplicationConfigRun {
    @Bean
    public ServerInfo serverInfo() {
        ServerInfo info = new ServerInfo();
        info.setIpNum("213.186.229.29");
        info.setPortNum("80");
        return info;
    }
}

 

     // 자바파일이므로 @Profile 어노테이션만 지정해주면 된다.

     [ServerInfo.java]

public class ServerInfo {
    private String ipNum;
    private String portNum;

    public String getIpNum() {
    	return ipNum;
    }

    public void setIpNum(String ipNum) {
    	this.ipNum = ipNum;
    }

    public String getPortNum() {
    	return portNum;
    }

    public void setPortNum(String portNum) {
    	this.portNum = portNum;
    }
} 

 

참고: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81-%EA%B0%95%EC%A2%8C/dashboard

반응형
Comments