사용자 도구

사이트 도구


spring:home

Spring

DI(Dependency Injection)와 IOC컨테이너

  1. DI(Dependency Injection) Dependency을 외부에서 만들어 넣어줌
  2. IOC컨테이너

사실 작은 규모의 프로젝트에서는 스프링의 DI사용을 하는 것 보다 일반적인 방법을 사용하여 개발하는 것이 더욱 빠르고, 개발에 따른 스트레스를 줄일 수 있습니다. 하지만 규모가 어느 정도 커지고, 추후 유지보수 업무가 발생시에는 DI를 이용한 개발의 장점을 느낄 수 있습니다.

Spring을 이용한 객체 생성과 조립

public static void main(String[] args) {
//		MyCalculator cal = new MyCalculator();
//		cal.setFirstNum(10);
//		cal.setSecondNum(2);
//		cal.add();
//		cal.sub();
//		cal.multi();
//		cal.divide();
  String configLocation = "classpath:applicationCTX.xml";
  AbstractApplicationContext ctx = new GenericXmlApplicationContext(configLocation);
  MyCalculator myCalculator = ctx.getBean("myCalculator", MyCalculator.class);
  myCalculator.add();
  myCalculator.sub();
  myCalculator.multi();
  myCalculator.divide();
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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">
 
	<!-- Root Context: defines shared resources visible to all other web components -->
 
	<bean id="calculator" class="com.taekgu.ex.Calculator"/>
	<bean id="myCalculator" class="com.taekgu.ex.MyCalculator">
		<property name="calculator">
			<ref bean="calculator"/>
		</property>
		<property name="firstNum" value="10"/>
		<property name="secondNum" value="2"/>
	</bean>
</beans>

Spring Property

Spring Container Life cycle

public class Student implements InitializingBean, DisposableBean {
.....
 
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("afterPropertiesSet()");
	}
 
	@Override
	public void destroy() throws Exception {
		System.out.println("destroy()");
	}
}

Spring Bean Scope

	<bean id="otherStudent" class="com.taekgu.ex.OtherStudent"
		init-method="initMethod" destroy-method="destoryMethod"
		scope="prototype|singleton">
		<constructor-arg value="홍길동"/>
		<property name="age">
			<value>10</value>
		</property>
		<property name="hobbys">
			<list>
				<value>Game</value>
				<value>Reading</value>
			</list>
		</property>
	</bean>

외부파일을 이용한 설정

  • Environment객체를 이용해서 스프링 빈 설정을 합니다.
  • Environment객체를 사용하지 않고 프로퍼티 파일을 직접 이용하여 스프링 빈을 설정하는 방법에 대해서 살펴 봅니다.
  • 동일한 스프링 빈을 여러 개 만들어 놓고 상황(환경)에 따라서 적절한 스프링 빈을 사용할 수 있습니다. profile 속성을 사용하면 됩니다.
<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"
	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">
	<!-- Root Context: defines shared resources visible to all other web components -->
 
	<context:property-placeholder location="classpath:admin.properties, classpath:sub_admin.properties" />
	<bean id="calculator" class="com.taekgu.ex.Calculator"/>
	<bean id="myCalculator" class="com.taekgu.ex.MyCalculator">
		<property name="calculator">
			<ref bean="calculator"/>
		</property>
		<property name="firstNum" value="10"/>
		<property name="secondNum" value="2"/>
	</bean>
	<bean id="otherStudent" class="com.taekgu.ex.OtherStudent"
		init-method="initMethod" destroy-method="destoryMethod"
		scope="prototype">
		<constructor-arg value="${adminUserName}"/>
		<property name="age">
			<value>10</value>
		</property>
		<property name="hobbys">
			<list>
				<value>Game</value>
				<value>Reading</value>
			</list>
		</property>
	</bean>
</beans>
Profile 이용
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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">
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="serverInfo" class="com.taekgu.ex.ServerInfo">
		<property name="serverAddress" value="localhost"></property>
		<property name="serverPort" value="8080"></property>
	</bean>
</beans>
public class MainEnv {
 
	public static void main(String[] args) {
		String config = null;
		Scanner scanner = new Scanner(System.in);
		String str = scanner.next();
		if(str.contentEquals("dev")) {
			config = "dev";
		} else if( str.contentEquals("prod")) {
			config = "prod";
		}
		scanner.close();
 
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
		ctx.getEnvironment().setActiveProfiles(config);
		ctx.load("applicationCTX_dev.xml","applicationCTX_prod.xml");
 
		ServerInfo info = ctx.getBean("serverInfo", ServerInfo.class);
		System.out.println("serverAddress=" + info.getServerAddress());
		System.out.println("serverPort=" + info.getServerPort());
		ctx.close();
	}
 
}

AOP(Aspect Oriented Promming : 관점지향프로그래밍)

프로그래밍을 하다 보면, 공통적인 기능이 많이 발생 합니다. 이러한 공통 기능을 모든 모듈에 적용하기 위한 방법으로 상속을 통한 방법이 있습니다. 상속도 좋은 방법이기는 하지만 몇 가지 문제가 있습니다.우선 JAVA에서는 다중 상속이 불가하므로 다양한 모듈에 상속기법을 통한 공통 기능 부여는 한계가 있습니다. 그리고, 기능 구현부분에 핵심 기능 코드와 공통 기능 코드가 섞여 있어 효율성이 떨어집니다.

위의 상속을 통한 방법에 한계가 있어 AOP가 등장하게 되었습니다. AOP방법은 핵심 기능과 공통 기능을 분리 시켜놓고, 공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식 입니다.

쉽게 생각해서 아침에 밥을 짓는다고 생각해 봅니다. 핵심 기능은 쌀을 씻고, 깨끗한 물을 적당히 넣고, 전자밥솥에 내솥을 넣고, 취사 버튼을 누르는 기능들 일 것입니다 공통 기능은 수도 꼭지를 열어 물을 받고, 쌀이 깨끗이 씻겼는지 눈으로 판단하고, 물을 적당한지 판단하는 기능들 일 것입니다. 이러한 기능이 공통 기능인 것은 밥을 짓는 행동이 아닐 때도 우리는 수도 꼭지를 열고, 눈으로 사물을 보고 적절한 판단을 하기 때문에 공통 기능이라고 하였습니다. 어쨌든, 이렇게 핵심 기능과 공통 기능을 분리해 놓고, 추후에 밥을 짓는 행동 말고 팥을 쑬 때도 핵심 기능은 변화지만, 공통 기능은 다시 적용할 수 있을 것입니다.

AOP 기법이 바로 이러한 것입니다. 공통 기능을 핵심 기능과 분리해 놓고, 공통 기능 중에서 핵심 기능에 적용하고자 하는 부분에 적용하는 것입니다.

AOP란?

Spring에서 AOP구현 방법 : proxy를 이용합니다. 스프링에서 AOP구현 방식

  • XML스키마기반의 AOP구현
  • @Aspect어노테이션기반의 AOP구현

용어정리

  • Aspect : 공통 기능
  • Advice : Aspect의 기능 자체
  • Jointpoint : Advice를 적용해야 되는 부분( ex, 필드, 메소드 ) (스프링에서는 메소드만 해당)
  • Pointcut : Jointpoint의 부분으로 실제로 Advice가 적용된 부분
  • Weaving : Advice를 핵심 기능에 적용 하는 행위
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" profile="dev"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="logAop" class="com.taekgu.ex.LogAop" />
	<aop:config>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="publicMethod"
				expression="within(com.taekgu.ex.*)" />
			<aop:around pointcut-ref="publicMethod" method="loggerAop" />
		</aop:aspect>
	</aop:config>
	<bean id="serverInfo" class="com.taekgu.ex.ServerInfo">
		<property name="serverAddress" value="localhost"></property>
		<property name="serverPort" value="8080"></property>
	</bean>
 
</beans>
package com.taekgu.ex;
 
import org.aspectj.lang.ProceedingJoinPoint;
 
public class LogAop {
	public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
		String signatureStr = joinpoint.getSignature().toShortString();
		System.out.println(signatureStr + "is start.");
		long st = System.currentTimeMillis();
		try {
			Object obj = joinpoint.proceed();
			return obj;
		} finally {
			long et = System.currentTimeMillis();
			System.out.println(signatureStr + " is finished.");
			System.out.println(signatureStr + " 경과시간 " + (et - st));
		}
   }
}
spring/home.txt · 마지막으로 수정됨: 2025/04/15 10:05 저자 127.0.0.1