Java EE 정리 39
22 Apr 2019
Reading time ~4 minutes
Java EE 정리 39 - Spring DI, Spring Container
Spring DI(Dependency Injection)
- 의존성 주입(이전명 = IoC, Inversion Of Control, 제어의 역행)
-
약결합
- 기능의 조립과 분해가 쉬워지도록 만드는 것
- Spring core
-
Spring Container들을 사용하여 객체가 생성되고 의존성 주입 설정
-
BeanFactory
- Bean들의 의존성 주입, 생명주기 관리
- Bean은 Spring Framework가 객체를 생성해주는 클래스
-
ApplicationContext(가장 많이 사용)
- Bean들의 의존성 주입, 생명주기 관리
- 파일 관리, 국제화 기능
-
BeanFactory
-
WebApplicationContext
- Bean들의 의존성 주입, 생명주기 관리
- 파일 관리, 국제화 기능
- Web에서 사용하는 기능
- WebApplication당 하나만 사용되어야 한다
- 설정용 XML이 사용되거나 아니면 Annotation으로 설정
-
설정용 XML
- 구조가 복잡한 대규모일 때 사용
- 객체간의 의존성 주입 관계를 한눈에 알 수 있다
- applicationContext.xml
<beans>
<bean id="">
...
</beans>
-
@Autowired, @Component
- 구조가 간단하고 처리하는 일이 많지 않은 경우 사용
- 소규모 Application, 단점은 어디서 의존성을 주입받는지 확인하기가 어렵다
- 객체간의 의존성 주입상태를 한눈에 파악하기 어렵다
약결합
-
Interface로 구현
- 인터페이스를 사용하여 약결합을 구현, 객체간의 유연성을 높일 수 있다
- Assembly에서 Service를 생성할 때 사용할 DAO를 주입, UseAssembly에서는 getBean()을 이용하여 의존성 주입으로 생성된 Service를 반환받아 사용
약결합 예
package kr.co.sist.vo;
public class EmpVO {
private int empno;
private String ename;
...
package kr.co.sist.dao;
public interface Dao {
public int insertEmp(EmpVO evo) throws SQLException;
public List<EmpVO> selectEmp() throws SQLException;
}
public class DAOOracleImpl implements Dao {
@Override
public int insertEmp(EmpVO evo) throws SQLException {
// Oracle DB에 insert 작업 수행
System.out.println("Oracle에 사원정보 추가");
return 1;
}
@Override
public List<EmpVO> selectEmp() throws SQLException {
List<EmpVO> list = new ArrayList<EmpVO>();
list.add(new EmpVO(1111, "노진경"));
list.add(new EmpVO(1112, "김희철"));
list.add(new EmpVO(1113, "김정윤"));
list.add(new EmpVO(1114, "이재찬"));
return list;
}
}
public class DAOMySqlImpl implements Dao {
@Override
public int insertEmp(EmpVO evo) throws SQLException {
// MySql DB에 insert 작업 수행
System.out.println("MySql에 사원정보 추가");
return 1;
}
@Override
public List<EmpVO> selectEmp() throws SQLException {
List<EmpVO> list = new ArrayList<EmpVO>();
list.add(new EmpVO(2111, "오영근"));
list.add(new EmpVO(2112, "공선의"));
list.add(new EmpVO(2113, "이재현"));
list.add(new EmpVO(2114, "이봉현"));
return list;
}
}
public interface Service {
public void addEmp(EmpVO evo);
public List<EmpVO> searchEmp();
}
-
인터페이스 Service를 구현한 ServiceImpl 클래스
-
자식이 아닌 부모의 이름으로 객체를 저장하면 모든 자식을 받을 수 있다
- == 객체 다형성
-
Service 객체는 업무를 처리하는데 반드시 Dao를 사용해야 한다
- == Service는 DAO에 의존성이 있다
- == Service객체를 사용하려면 DAO를 의존성 주입(DI)받아야 한다
-
자식이 아닌 부모의 이름으로 객체를 저장하면 모든 자식을 받을 수 있다
public class ServiceImpl implements Service {
private Dao dao;
public ServiceImpl(Dao dao) { // 의존성 주입(DI)
this.dao = dao;
}
@Override
public void addEmp(EmpVO evo) {
try {
// 업무로직을 처리
System.out.println("추가 작업에 대한 업무로직 처리");
dao.insertEmp(evo);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public List<EmpVO> searchEmp() {
List<EmpVO> list = null;
try {
System.out.println("조회작업에 대한 업무로직 처리");
list = dao.selectEmp();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
-
Assembly 클래스
- 의존성 주입 관계를 설정하는 일
-
Assembly의 일은 Spring Framework이 대신 수행해줌
- 의존성 주입할 객체를 생성
- 의존성 주입받을 객체를 생성하면서 의존성 주입
- 의존성 주입받은 객체를 반환
/**
* 의존성 주입 관계를 설정하는 일
*/
public class Assembly {
public Service getBean() {
// 1. 의존성 주입할 객체를 생성
Dao dao = new DAOOracleImpl();
// 2. 의존성 주입받을 객체를 생성하면서 의존성 주입
Service service = new ServiceImpl(dao);
// 3. 의존성 주입받은 객체를 반환
return service;
}
}
/**
* 조립자 클래스(Assembly)를 사용하여 서비스 객체를 얻고
* 서비스를 사용하는 일을 한다
*/
public class UseAssembly {
public static void main(String[] args) {
Assembly as = new Assembly();
Service service = as.getBean();
service.addEmp(new EmpVO(3111, "피카츄"));
System.out.println("-----------------------");
List<EmpVO> list = service.searchEmp();
for(EmpVO emp : list) {
System.out.println(emp.getEmpno()+" / "+emp.getEname());
}
}
}
- 약결합이므로 DAO를 변경할 때 Service 내부를 고치는게 아니라 Assembly(조립자 클래스)만 고치면 됨
public class Assembly {
public Service getBean() {
// 1. 의존성 주입할 객체를 생성
Dao dao = new DAOMySqlImpl();
// 2. 의존성 주입받을 객체를 생성하면서 의존성 주입
Service service = new ServiceImpl(dao);
// 3. 의존성 주입받은 객체를 반환
return service;
}
}
- Assembly가 하는 일을 Spring Container가 함
Spring Container
- BeanFactory, ApplicationContext, WebApplicationContext가 제공
- 객체간의 의존성 주입을 쉽게 해준다
- org.springframework.context package에서 제공
- 의존성 주입의 정보는 설정용 xml에서 정의
- Spring Container가 생성하고 관리하는 클래스를 Bean이라고 한다
- Spring Container는 commons-logging.jar에 의존성이 있다
Spring Container 사용법
-
설정용 XML 생성
- 정의된 클래스는 사용여부에 상관없이 모두 객체가 생성된 상태에서 실행된다
- 객체는 Singleton Pattern으로 생성된다
<!-- applicationContext.xml -->
<beans>
<!-- 객체를 생성 -->
<bean id="객체명" class="객체화할 클래스">
...
<!-- 의존성 주입, 인터페이스가 없이 객체가 추가됨 -->
<bean id="객체명" class="객체화할 클래스">
<constructor-arg ref="의존성 주입할 객체명"/>
</bean>
...
</beans>
- Spring Container를 생성
ApplicationContext ac = new ClassPathXmlApplicationContext("설정용 xml");
- 의존성 주입받은 객체를 얻는다
// 스프링 ~ 2.5.x, 캐스팅해서 사용
ServiceImpl si = (ServiceImpl)ac.getBean("beanId")
// 스프링 3.x 이상
ServiceImpl si = ac.getBean("beanId", "의존성주입받을클래스.class);
-
Spring Bean Configuration File 생성
- Assembly의 일을 해줌
<!-- applicationContext.xml -->
...
<beans ...>
<!-- 의존성 주입할 객체를 생성 -->
<bean id="dao" class="kr.co.sist.dao.DAOOracleImpl"/>
<bean id="my_sql" class="kr.co.sist.dao.DAOMySqlImpl"/>
<!-- 의존성 주입받을 객체 생성 -->
<bean id="service" class="kr.co.sist.service.ServiceImpl">
<!-- 의존성 주입 -->
<constructor-arg ref="dao"/>
</bean>
</beans>
public class UseSpringContainer {
public static void main(String[] args) {
// 1. 설정파일을 사용하여 Spring Container생성
ApplicationContext ac = new ClassPathXmlApplicationContext("kr/co/sist/di/applicationContext.xml");
// 2. id를 사용하여 Bean(의존성 주입받은 객체) 얻기
// ServiceImpl si = (ServiceImpl)ac.getBean("service");
ServiceImpl si = ac.getBean("service",ServiceImpl.class);
// 3. 찾아낸 Bean을 사용하여 출력
si.addEmp(new EmpVO(3333, "김정윤"));
List<EmpVO> list = si.searchEmp();
for(EmpVO ev : list) {
System.out.println(ev.getEmpno()+"/"+ev.getEname());
}
}
}
- common-logging을 다운로드, 외부 라이브러리를 Build Path로 추가