제어의 역행(IoC, Inversion of Control)
객체, 메서드 호출시 처리하지않고 외부(spring)에서 처리한다.
블럭 끼워넣기
개발이라고도 칭함
의존성 주입(DI, Dependency Injection)
제어의 역행이 발생할 때, 스프링 내부에 있는 객체가 해당 클래스를 사용할 때 필요한 관계를 관리하는 동작 또는 기법
여기서 의존성이란 객체가 혼자서는 처리할 수 없음을 뜻한다.
따라서 객체를 직접 생성해서 구현한다 ex) jsp model2에서의 DAO객체생성
관계를 약화시키면서 간접 구현 즉 호출해야한다.
따라서 의존성 주입이란 객체를 직접 생성/제어하는 것이 아니라, 제어의 역행을 사용해서 특정 객체를 필요한 객체의 외부에 가져다가 연결하는 것을 뜻한다.
객체가 필요한 어떤 객체를 생성자 혹은 setter를 통해 주입하는 것을 말한다.
예를 들어 사람이란 객체가 있다. 머리, 몸통, 팔, 다리부분으로 구성되어있는 객체이다. 여기서 머리만 바꿔끼우면(= 주입) 사람A에서 사람B가 될 수 있다.
의존성 주입 3가지 방법 스프링 프레임워크는 @Autowired
애노테이션을 이용하여 다양한 의존성주입방법을 제공한다.@Autowired
애노테이션은 Spring에게 의존성을 주입하라는 지시자 역할로 쓰이는데 생성자, 필드, 세터에 붙일 수 있다.
생성자 주입
@Autowired 애노테이션 생략가능 -> lombok을 활용해 @ReqyiredArgsConstructor와 상수 조합1 2 3 4 5 @RestController @ReqyiredArgsConstructor public class ApiController { private final UserService service; }
필드 주입: 변수 선언부에 @Autowired 애노테이션을 붙인다.
가장 편리한 방법이면서 실무에서 자주 사용하는 주입 방법1 2 3 4 5 @RestController public class ApiController { @Autowired private UserService service; }
수정자 주입(Setter): Setter 메소드에 @Autowired 애노테이션을 붙인다. 1 2 3 4 5 6 7 8 9 @Component public class ApiController { private UserService userService; @Autowired public void setUserService (UserService userService) { this .userService = userService; } }
위의 세가지 방법 중 spring에서 권장하는 방법은 생성자를 통한 주입 방법이다. 생성자주입방법이 좋은 이유는 순환참조 방지, 테스트 코드 작성 용이하기 때문이다.
어노테이션을 쓰지않고 xml을 이용한 DI 1 생성자를 이용한 예시
.xml
파일에 spring beans DTD 연결
.xml파일의 <bean>태그
로 객체생성하기 (new 키워드랑 동일한 결과)
constructor-arg : “생성자 사용해서 값 주입”
원하는 파라미터 갯수만큼 <constructor-arg>
태그생성
태그 생성시 순서 : 파라미터 순서그대로 대입됨
student.xml
코드
value담는 방식은 두가지 1. <value>
태그사용 2.value=""
속성사용1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" > <beans > <bean id ="studentBean" class ="com.itwill.spring.ItwillStudent" > <property name ="name" value ="홍길동" > </property > <property name ="classNum" > <value > 7</value > </property > </bean > <bean id ="conBean1" class ="com.itwill.spring.ItwillStudent" > <constructor-arg > <value > 사용자3</value > </constructor-arg > </bean > <bean id ="conBean2" class ="com.itwill.spring.ItwillStudent" > <constructor-arg value ="사용자4" /> <constructor-arg value ="1" /> </bean > </beans >
Student.java
인터페이스 생성
1 2 3 4 5 public interface Student { public void showInfo () ; }
ItwillStudent.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 31 public class ItwillStudent implements Student { private String name; private int classNum; public ItwillStudent () {} public ItwillStudent (String name) { this .name = name; } public ItwillStudent (String name,int classNum) { this .name = name; this .classNum = classNum; } public void setName (String name) { this .name = name; } public void setClassNum (int classNum) { this .classNum = classNum; } @Override public void showInfo () { System.out.println("이름: " + name + ", 강의장: " + classNum); } @Override public String toString () { return "toString [이름: " + name + ", 강의장: " + classNum + "]" ; } }
StudentTest.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 public class StudentTest { public static void main (String[] args) { ItwillStudent kim = new ItwillStudent(); kim.setName("킴스" ); kim.setClassNum(8 ); kim.showInfo(); System.out.println("-----생성자 사용하여 객체생성" ); ItwillStudent user1 = new ItwillStudent("사용자1" ); user1.showInfo(); Student user2 = new ItwillStudent("사용자2" , 7 ); user2.showInfo(); System.out.println("-----생성자 사용하여 DI" ); ItwillStudent user3 = (ItwillStudent) fac.getBean("conBean1" ); user3.showInfo(); ItwillStudent user4 = (ItwillStudent) fac.getBean("conBean2" ); user4.showInfo(); } }
2 수정자 Setter메서드 이용한 예시
.xml
파일에 spring beans DTD 연결
.xml파일의 <bean>태그
로 객체생성하기 (new 키워드랑 동일한 결과)
bean태그에서 사용할 수 있는 속성들
id : “빈 객체의 고유한 이름, 외부에서 접근하는 이름”
name : “객체의 별칭”
class : “생성할 클래스위치”
property : “set() 사용해서 값을 주입”
name속성 : bean태그의 class속성 위치에 있는 클래스의 멤버변수 중에 set 원하는 것을 지정
value담는 방식은 두가지 1. <value>
태그사용 2.value=""
속성사용
constructor-arg : “생성자 사용해서 값 주입”
person.xml
코드1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" > <beans > <bean id ="personBean" class ="com.itwill.spring.SubPerson" > <property name ="name" > <value > 아이린</value > </property > <property name ="age" value ="25" > </property > </bean > </beans >
IPerson.java
인터페이스생성
1 2 3 4 5 6 public interface IPerson { public void sayHello () ; }
SubPerson.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 public class SubPerson implements IPerson { private String name; private int age; public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } @Override public void sayHello () { System.out.println(name+"님(" +age+"세), 안녕하세요!" ); } @Override public String toString () { return "SubPerson정보 [이름=" + name + ", 나이=" + age + "]" ; } }
PersonTest.java
파일에서 객체 사용하기
BeanFactory는 외부의 파일을 읽어와서 처리함
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 33 34 35 public class PersonTest { public static void main (String[] arg) { Person p1 = new Person(); p1.setName("홍길동" ); p1.setAge(20 ); System.out.println(p1); System.out.println(p1.toString()); SubPerson sp = new SubPerson(); sp.setName("소미" ); sp.setAge(22 ); sp.sayHello(); BeanFactory fac = new XmlBeanFactory(new FileSystemResource("person.xml" )); IPerson ip = (IPerson) fac.getBean("personBean" ); ip.sayHello(); } } 사용자정보 [이름=홍길동, 나이=20 ] 사용자정보 [이름=홍길동, 나이=20 ] 소미님(22 세), 안녕하세요! log4j:WARN No appenders could be found for logger (org.springframework.beans.factory.xml.XmlBeanDefinitionReader) . log4j:WARN Please initialize the log4j system properly. log4j:WARN See http: 아이린님(25 세) , 안녕하세요!
강한 결합 VS 약한 결합
JPA에서 주로 사용하는 DI 방법은? 빌더 패턴을 사용하기를 권장하고 있다. 그 이유는 생성패턴의 종류와 빌더패턴을 사용해야하는 이유 포스팅에서 확인할 수 있다.