스프링 삼각형과 설정 정보
IoC/DI - 제어의 역전/의존성 주입
프로그래밍에서 의존성이란?
- 집합 관계: 부분이 전체와 다른 생명 주기를 가질 수 있음 (집 - 냉장고)
- 구성 관계: 부분은 전체와 같은 생명 주기를 가짐 (사람 - 심장)


pacakge expert001_01;
interface Tire {
String getBrand();
}
pacakge expert001_01;
public class KoreaTire implements Tire {
public String getBrand() {
return "코리아 타이어";
}
}
pacakge expert001_01;
public class AmericaTire implements Tire {
public String getBrand() {
return "미국 타이어";
}
}
package expert001_01;
public class Car {
Tire tire;
public Car() {
tire = new KoreaTire();
// tire = new AmericaTire();
}
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}
package expert001_01;
public class Car {
Tire tire;
public Car() {
tire = new KoreaTire();
// tire = new AmericaTire();
}
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}
package expert001_01;
public class Driver {
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.getTireBrand());
}
}
package expert001_01;
import static org.junit.Assert.*;
import org.junit.Test;
public class CarTest {
@Test
public void 자동차_장착_타이어브랜드_테스트() {
Car car = new Car();
assertEquals("장착된 타이어: 코리아 타이어", car.getTireBrand());
}
}
스프링 없이 의존성 주입하기 1 - 생성자를 통한 의존성 주입
- 주입이란?
- 자동차 내부에서 타이어를 생산하는 것이 아니라 외부에서 생산된 타이어를 자동차에 장착


package expert001_02;
public interface Tire {
String getBrand();
}
pacakge expert001_02;
public class KoreaTire implements Tire {
public String getBrand() {
return "코리아 타이어";
}
}
pacakge expert001_02;
public class AmericaTire implements Tire {
public String getBrand() {
return "미국 타이어";
}
}
package expert001_02;
public class Car {
Tire tire;
public Car(Tire tire) {
this.tire = tire;
}
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}
package expert001_02;
public class Driver {
public static void main(String[] args) {
Tire tire = new KoreaTire();
//Tire tire = new AmericaTire();
Car car = new Car(tire);
System.out.println(car.getTireBrand());
}
}
package expert001_02;
import static org.junit.Assert.*;
import org.junit.Test;
public class CarTest {
@Test
public void 자동차_코리아타이어_장착_타이어브랜드_테스트() {
Tire tire1 = new KoreaTire();
Car car1 = new Car(tire1);
assertEquals("장착된 타이어: 코리아 타이어", car1.getTireBrand());
}
@Test
public void 자동차_미국타이어_장착_타이어브랜드_테스트() {
Tire tire2 = new AmericaTire();
Car car2 = new Car(tire2);
assertEquals("장착된 타이어: 미국 타이어", car2.getTireBrand());
}
}
스프링 없이 의존성 주입하기 2 - 속성을 통한 의존성 주입

package expert001_03;
public class Car {
Tire tire;
public Tire getTire() {
return tire;
}
public void setTire(Tire tire) {
this.tire = tire;
}
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}
package expert001_03;
public class Driver {
public static void main(String[] args) {
Tire tire = new KoreaTire();
Car car = new Car();
car.setTire(tire);
System.out.println(car.getTireBrand());
}
}
package expert001_03;
import static org.junit.Assert.*;
import org.junit.Test;
public class CarTest {
@Test
public void 자동차_코리아타이어_장착_타이어브랜드_테스트() {
Tire tire1 = new KoreaTire();
Car car1 = new Car();
car1.setTire(tire1);
assertEquals("장착된 타이어: 코리아 타이어", car1.getTireBrand());
}
@Test
public void 자동차_미국타이어_장착_타이어브랜드_테스트() {
Tire tire2 = new AmericaTire();
Car car2 = new Car();
car2.setTire(tire2);
assertEquals("장착된 타이어: 미국 타이어", car2.getTireBrand());
}
}
스프링을 통한 의존성 주입 - XML 파일 사용

package expert002;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Driver {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("expert002/expert002.xml");
Car car = new Car();
car.setTire(tire);
System.out.println(car.getTireBrand());
}
}
<?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">
<bean id="tire" class="expert002.KoreaTire"></bean>
<bean id="americaTire" class="expert002.AmericaTire"></bean>
<bean id="car" class="expert002.Car"></bean>
</beans>

package expert003;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpiringJUnit4ClassRunner.class)
@ContextConfiguration("expert003.xml")
public class CarTest {
@Autowired
Car car;
@Test
public void 자동차_코리아타이어_장착_타이어브랜드_테스트() {
assertEquals("장착된 타이어: 코리아 타이어", car.getTireBrand());
}
}
스프링을 통한 의존성 주입 - @Autowired를 통한 속성 주입
<?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"
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.1.xsd">
<context:annotation-config />
<bean id="tire" class="expert004.KoreaTire"></bean>
<bean id="americaTire" class="expert004.AmericaTire"></bean>
<bean id="car" class="expert004.Car"></bean>
</beans>
property태그가 사라지고@Autowired를 통해car의property를 자동으로 엮어 줌
package expert004;
import org.springframework.beans.factory.annotation.Autowired;
public class Car {
@Autowired
Tire tire;
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}

스프링을 통한 의존성 주입 - @Resource를 통한 속성 주입
package expert005;
import javax.annotation.Resource;
public class Car {
@Resource
Tire tire;
public String getTireBrand() {
return "장착된 타이어: " + tire.getBrand();
}
}
- @Resource 는 자바 표준 어노테이션, type과 id 중 type 우선 매칭
- @Autowired 는 스프링 어노테이션, type과 id 중 id 우선 매칭
스프링을 통한 의존성 주입 - @Autowired vs. @Resource vs.
태그
| @Autowired | @Resource | |
|---|---|---|
| 출처 | 스프링 프레임워크 | 표준 자바 |
| 소속 패키지 | org.springframework.beans.factory.annotaion.Autowired | javax.annotation.Resource |
| 빈 검색 방식 | byType 먼저, 못 찾으면 byName | byName 먼저, 못 찾으면 byType |
| 특이사항 | @Qualifer(“”) 협업 | name 어트리뷰트 |
| byName 강제하기 | @Autowired @Qualifier(“tire1”) | @Resource(name=”tire1”) |
AOP - Aspect? 관점? 핵심 관심사? 횡단 관심사?
- AOP: Aspect-Oriented Programming
- 횡단 관심사 (cross-cutting concern): 다수의 모듈에 공통적으로 나타나는 부분
- 핵심 관심사: 모듈별로 고유한 부분

package aop001;
public class Boy {
public void runSomething() {
System.out.println("열쇠로 문을 열고 집에 들어간다.");
try {
System.out.println("컴퓨터로 게임을 한다.");
} catch (Exception ex) {
if (ex.getMessage().equals("집에 불남")) {
System.out.println("119 에 신고한다.");
}
} finally {
System.out.println("소등하고 잔다.");
}
System.out.println("자물쇠를 잠그고 집을 나선다.");
}
}
package aop001;
public class Girl {
public void runSomething() {
System.out.println("열쇠로 문을 열고 집에 들어간다.");
try {
System.out.println("요리를 한다.");
} catch (Exception ex) {
if (ex.getMessage().equals("집에 불남")) {
System.out.println("119 에 신고한다.");
}
} finally {
System.out.println("소등하고 잔다.");
}
System.out.println("자물쇠를 잠그고 집을 나선다.");
}
}
package aop001;
public class Start {
public static void main(String[] args) {
Boy romeo = new Boy();
Girl juliet = new Girl();
romeo.runSomething();
juliet.runSomething();
}
}

일단 덤벼 보자 - 실전편
package aop002;
public interface Person {
void runSomething();
}
package aop002;
public class Boy implements {
public void runSomething() {
System.out.println("컴퓨터로 게임을 한다.");
}
}
package aop002;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop002/aop002.xml");
Person romeo = context.getBean("boy", Person.class);
romeo.runSomething();
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop002.MyAspect" />
<bean id="boy" class="aop002.Boy" />
</beans>
package aop002;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.JoinPoint;
@Aspect
public class MyAspect {
@Before("execution(public void aop002.Boy.runSomething())")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
// System.out.println("열쇠로 문을 열고 집에 들어간다.");
}
}
@Aspect는 이 클래스를 AOP에서 사용하겠다는 의미@Before는 대상 메서드 실행 전에 이 메서드를 실행하겠다는 의미- 실행 결과
얼굴 인식 확인: 문을 개방하라 컴퓨터로 게임을 한다.일단 덤벼 보자 - 설명편



- 초록색 부분: 횡단 관심사
- 붉은색 부분: 스프링 AOP가 인터페이스 기반으로 작동하므로 필요 (
Person.java) MyAspect.java:Boy와Girl에서 나타나는 횡단 관심사 처리<aop:aspectj-autoproxy />: 프록시 패턴을 이용해 횡단 관심사를 핵심 관심사에 주입- 스프링 AOP는
- 인터페이스 기반
- 프록시 기반
- 런타임 기반
일단 덤벼 보자 - 용어편
Pointcut - 자르는 지점? Aspect 적용 위치 지정자!
package aop002;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* runSomething())")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
}
@Before("execution(* runSomething())"): 선언한 메소드 (before)를* runSomething이 실행되기 전에 실행- 타겟 메서드 지정자:
[접근제한자패턴] 리턴타입패턴 [패키지&클래스패턴] 메서드이름패턴(파라미터패턴) [throws 예외패턴]JoinPoint - 연결점? 연결 가능한 지점!
Pointcut은JoinPoint의 부분 집합Aspect적용이 가능한 모든 지점romeo.runSomething()메서드를 호출한 상태라면JoinPoint는romeo객체의runSomething()메서드- 넓은 의미의
JoinPoint란Aspect적용이 가능한 모든 지점 - 좁은 의미의
JoinPoint란 호출된 객체의 메서드Advice - 조언? 언제, 무엇을!
PointCut에 언제, 무엇을 적용할 지 정의한 메서드Aspect - 관점? 측면? Advisor의 집합체!
- 여러 개의
Advice와 여러 개의PointCut의 결합체Advisor - 조언자? 어디서, 언제, 무엇을!
Advisor= 한 개의Advice+ 한 개의PointCut- 스프링 AOP에서만 사용
일단 덤벼 보자 - POJO와 XML 기반 AOP
package aop003;
import org.aspectj.lang.JoinPoint;
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
//System.out.println("열쇠로 문을 열고 집에 들어간다.");
}
}

package aop004;
import org.aspectj.lang.JoinPoint;
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
public void lockDoor(JoinPoint joinPoint) {
System.out.println("주인님 나갔다: 어이 문 잠가!!!");
}
}
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop004.MyAspect" />
<bean id="boy" class="aop004.Boy" />
<bean id="girl" class="aop004.Girl" />
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* runSomething())" id="iampc"/>
<aop:before method="before" pointcut-ref="iampc" />
<aop:after method="lockDoor" pointcut-ref="iampc" />
</aop:aspect>
</aop:config>
</beans>
- 어노테이션 기반
package aop005;
import org.aspect.lang.JoinPoint;
import org.aspect.lang.annotation.After;
import org.aspect.lang.annotation.Aspect;
import org.aspect.lang.annotation.Before;
@Aspect
public class MyAspect {
@Pointcut("execution(* rumSomething())")
private void iampc() {
// 여긴 무엇을 작성해도 의미가 없어요.
}
@Before("iampc()")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
@After("iampc()")
public void lockDoor(JoinPoint joinPoint) {
System.out.println("주인님 나갔다: 어이 문 잠가!!!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans
...생략... >
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop005.MyAspect" />
<bean id="boy" class="aop005.Boy" />
<bean id="girl" class="aop005.Girl" />
</beans>
PSA - 일관성 있는 서비스 추상화
- Portable Service Abstraction
- 어댑터 패턴을 적용해 같은 일을 하는 다수의 기술을 공통의 인터페이스로 제어
- JDBC (
Connection,Statement,ResultSet)
- JDBC (
- 스프링에서는 OXM (Object XML Mapping), ORM, 캐시, 트랜잭션 등 다양한 기술에 대한 PSA 제공