개발자입니다
[비트캠프] 80일차(17주차2일) - Spring Framework(Spring IoC 컨테이너) 본문
[비트캠프] 80일차(17주차2일) - Spring Framework(Spring IoC 컨테이너)
끈기JK 2023. 2. 28. 17:27
59 Spring IoC 컨테이너
Servlet Container 가 관리(생성 → 소멸)하는 것들이다.
서블릿 - DispatcherServlet
- JSP
필터 - AuthFilter
- CharacterEncodingFilter
리스너 - ContextLoaderListener
ContextLoaderListener 가 관리(생성 → 소멸)하는 것들이다.
- Mybatis
- DAO
- Service
- Page Controller
↓ 관리 위임
Spring IoC 컨테이너
ContextLoaderListener 를 Spring IoC 컨테이너로 변경한다.
《interface》ApplicationContext
- 빈 팩토리 객체 관리
- 일반 파일 자원 로딩
- 리스너 등록
- I18N 메시지 조회
...
이를 구현한 객체이다.
《concrete》FileSystemXmlApplicationContext 절대 경로(파일 시스템) c:\a\b\k.xml → IoC 컨테이너 설정 파일(.xml)
《concrete》ClassPathXmlApplicationContext 자바 클래스 경로 → IoC 컨테이너 설정 파일(.xml)
《concrete》AnnotationConfigApplicationContext 자바 클래스 파일의 애노테이션으로 IoC 컨테이너 설정 → 애노테이션(.class)
ApplicationContext를 상속한 《interface》WebApplicationContext 가 있다.
- 웹정보 다루는 기능
이를 구현한 객체이다.
《concrete》AnnotationConfigWebApplicationContext → 애노테이션(.class)
《concrete》XmlWebApplicationContext → IoC 컨테이너 설정 파일(.xml)
Inversion of Control (제어의 역전, 역제어)
- 의존객체(작업을 수행하기 위해서 사용하는 객체(도구)) 직접 생성 → 주입(Dependency Injection(DI)) 받기
→ IoC 컨테이너 = Bean(자바 객체) 생성, 소멸 관리 → "Bean Container"
- 메서드 직접 호출(작업을 수행하는 메서드를 호출) → 호출 당하기(특정 상황에서 호출될 메서드(Listener, Callback)를 등록)
일반적인 순방향 제어에서 역방향 제어로 변경하는 방식이 IoC
spring-context 라이브러리 추가
central.sonatype.com 에서 "spring-context" 검색해서 6.0.5 버전 코드 build.gradle 에 복붙하고 $ gradle eclipse 한다.
라이브러리에 spring 관련 .jar 생성된다.
59 Spring IoC 컨테이너 - 관리 대상 클래스 지정하기
@Componenet 세분화 ← 애노테이션을 붙인 클래스에 대해 자동으로 객체를 생성한다.
- @Controller ← 페이지 컨트롤러에 붙이는 애노테이션
- @RestController ← 페이지 컨트롤러에 붙이는 애노테이션
- @Service
- @Repository ← DAO 에 붙이는 애노테이션
역할에 따라 애노테이션을 붙이면 객체를 분류하기 쉽다. 즉 객체를 역할별로 제어할 수 있다.
Spring-web 라이브러리 추가
central.sonatype.com 에서 "spring-webc" 검색해서 6.0.5 버전 코드 build.gradle 에 복붙하고 $ gradle eclipse 한다.
spring-web 이 추가된다.
59 Spring IoC 컨테이너 - 의존 객체 주입
생성자가 없어도 필드에 자동 주입되게 하려면 필드 선언 앞에 @Autowired 를 앞에 붙인다.
### 59. Spring IoC 컨테이너 도입하기: 객체 생성 자동화
- Spring IoC 컨테이너를 사용하여 객체를 자동으로 생성하는 방법
- @Autowired를 사용하여 의존 객체를 자동으로 주입하는 방법
- Java Config를 사용하여 설정하는 방법
- @Bean 을 이용하여 메서드 리턴 값을 컨테이너에 보관하는 방법
- @ComponentScan 을 이용하여 IoC 컨테이너가 관리할 패키지 영역을 지정하는 방법
myapp.config 패키지 생성하고 AppConfig.java 파일 생성한다.
@Configuration 은 @Component, @Service, @Repository, @Controller 가 붙은 클래스를 자동 스캔하여 Bean 으로 등록 한다.
@ComponentScan 으로 스캔 범위 지정할 수 있다.
서버 실행으로 웹 앱 시작시 생성할 객체의 메서드를 @Bean 으로 지정한다.
@Bean(name=" ") 으로 이름 지정하지 않으면 인스턴스 명을 카멜 표기법 사용하여 객체 생성한다.
메서드 리턴 값으로 인스턴스 생성 코드 입력한다.
//@Configuration
// Spring IoC 컨테이너가 자동 생성할 클래스를 찾을 수 있도록 패키지를 지정한다.
@ComponentScan("bitcamp.myapp")
public class AppConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
System.out.println("SqlSessionFactory 객체 생성!");
InputStream mybatisConfigInputStream = Resources.getResourceAsStream(
"bitcamp/myapp/config/mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
return new BitcampSqlSessionFactory(
builder.build(mybatisConfigInputStream));
}
@Bean
public TransactionManager transactionManager(SqlSessionFactory sqlSessionFactory) throws Exception {
System.out.println("TransactionManager 객체 생성! ");
return new TransactionManager((BitcampSqlSessionFactory) sqlSessionFactory);
}
@Bean
public BoardDao boardDao(SqlSessionFactory sqlSessionFactory) {
return new DaoGenerator(sqlSessionFactory).getObject(BoardDao.class);
}
@Bean
public MemberDao memberDao(SqlSessionFactory sqlSessionFactory) {
return new DaoGenerator(sqlSessionFactory).getObject(MemberDao.class);
}
@Bean
public StudentDao studentDao(SqlSessionFactory sqlSessionFactory) {
return new DaoGenerator(sqlSessionFactory).getObject(StudentDao.class);
}
@Bean
public TeacherDao teacherDao(SqlSessionFactory sqlSessionFactory) {
return new DaoGenerator(sqlSessionFactory).getObject(TeacherDao.class);
}
@Bean
public BoardFileDao boardFileDao(SqlSessionFactory sqlSessionFactory) {
return new DaoGenerator(sqlSessionFactory).getObject(BoardFileDao.class);
}
}
IoC Container 객체 생성시 이 클래스의 .class 스태틱 변수를 전달해 AppConfig.java 에 @Bean 이 붙은 메서드를 Bean 으로 등록한다. 추후 getBean 으로 객체 얻는다.
@Controller 가 붙은 클래스를 찾아 Bean 및 메서드를 필드에 저장한다.
메서드 중에서 @RequestMapping 이 붙은 메서드의 value 를 맵에 key 로, RequestHandlerMapping 객체에 controller와 메서드 객체를 생성자 매개변수로 전달한 신규 객체를 value 로 저장한다.
@MultipartConfig(maxFileSize = 1024 * 1024 * 50)
@WebServlet(
value = "/app/*", // 서블릿의 요청 URL
loadOnStartup = 1 // 웹애플리케이션이 시작되었을 때 즉시 생성하도록 설정
)
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
ApplicationContext appCtx;
Map<String,RequestHandlerMapping> requestHandlerMap = new HashMap<>();
@Override
public void init() throws ServletException {
try {
// 프론트 컨트롤러가 사용할 페이지 컨트롤러 준비
appCtx = new AnnotationConfigApplicationContext(AppConfig.class);
// 스프링 IoC 컨테이너에 등록된 객체들
String[] beanNames = appCtx.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.printf("%s ==> %s\n", beanName, appCtx.getBean(beanName).getClass().getName());
}
// 요청 핸들러 준비하기
prepareRequestHandlers();
} catch (Exception e) {
System.out.println("객체 준비 중 오류 발생!");
e.printStackTrace();
}
}
/* 중략 */
private void prepareRequestHandlers() throws Exception {
String[] controllerNames = appCtx.getBeanNamesForAnnotation(Controller.class);
for (String controllerName : controllerNames) {
Object controller = appCtx.getBean(controllerName);
Method[] methods = controller.getClass().getDeclaredMethods();
for (Method m : methods) {
RequestMapping anno = m.getAnnotation(RequestMapping.class);
if (anno == null) continue;
requestHandlerMap.put(anno.value()[0], new RequestHandlerMapping(controller, m));
System.out.println(controller.getClass().getName() + "." + m.getName() + "() 요청 핸들러 등록!");
}
}
}
}
@Autowired 사용하면 매개변수를 받는 생성자 코드를 작성할 필요 없다.
스프링 프레임워크가 객체 생성시 @Autowired 가 붙은 필드에 값 넣어준다.
@Controller
public class AuthController {
@Autowired private StudentService studentService;
@Autowired private TeacherService teacherService;
@Controller
public class BoardController {
@Autowired private BoardService boardService;
@Controller
public class DownloadController {
@Autowired private BoardService boardService;
@Controller
public class StudentController {
@Autowired private StudentService studentService;
@Controller
public class TeacherController {
@Autowired private TeacherService teacherService;
service 객체도 @Service 붙여서 Bean 등록할수 있게 한다.
@Autowired 로 필요한 값 받는다.
@Service
public class DefaultBoardService implements BoardService {
@Autowired private TransactionManager txManager;
@Autowired private BoardDao boardDao;
@Autowired private BoardFileDao boardFileDao;
@Service
public class DefaultStudentService implements StudentService {
@Autowired private TransactionManager txManager;
@Autowired private MemberDao memberDao;
@Autowired private StudentDao studentDao;
@Service
public class DefaultTeacherService implements TeacherService {
@Autowired private TransactionManager txManager;
@Autowired private MemberDao memberDao;
@Autowired private TeacherDao teacherDao;
Spring-webMVC 라이브러리 추가
central.sonatype.com 에서 "spring-webmvc" 검색해서 6.0.5 버전 코드 build.gradle 에 복붙한다.
Spring WebMVC 6.x 버전 사용하려면 Jakarta EE 9 사용해야 하므로 5.3.25 로 버전 수정한다.
$ gradle eclipse 한다.
spring-context, spring-web 의존 라이브러리 자동 추가 되므로 주석 처리한다.
Java EE 와 Servlet/JSP 기술 규격
Java EE : 기업용 App 개발과 관련된 기술 모음
Java Enterprise Edition
- Servlet/JSP : 웹기반 Application 배치 및 실행 다중, 동시 사용자용 App 개발 기술
- EJB(Enterprise JavaBeans) : 분산 App. 제작이 필요한 Component 개발 기술
- Web Service
- 자원 공유
- 트랜잭션 관리
인사시스템을 회계시스템에서 객체.call(분산객체) 한다.
분산 : 멀리 떨어져 있는 객체 = 원격 객체 = 다른 컴퓨터, 다른 프로세스 에서 생성한 객체
Java EE 와 Servlet/JSP 기술 규격 버전
Jakarta EE 8 / Java EE 8 까지는 Oracle이, 여기부터는 Eclipse 재단이 관리한다.
Java EE 와 Servlet/JSP 기술 규격 서버
Servlet, JSP 기술을 사용할 수 있는 것은 Tomcat, Resin, Jetty, Undertow - "Servlet Container" 이다.
Servlet, JSP, EJB 기술을 사용할 수 있는 것은 JEUS(TmaxSoft), WebLogic(Oracle), WebSphere(IBM), JBoss(RedHat), Geronemo(Apache), GlassFish(Oracle) - "Java EE Implements" (Java EE 구현체) = Java EE 서버
서버 버전과 기술 규격
Tomcat 5.x → Servlet 2.4 / JSP 2.0
Tomcat 6.x → Servlet 2.5 / JSP 2.1
Tomcat 7.x → Servlet 3.0 / JSP 2.2
Tomcat 8.x → Servlet 3.1 / JSP 2.3
Tomcat 9.x → Servlet 4.0 / JSP 2.3
→ 여기까지 Java EE (javax.servlet.*)
→ 여기부터 Jakarta EE (jakarta.servlet.*) 패키지 변경
Tomcat 10.x → Servlet 6.0 / JSP 3.1
Spring WebMVC Framework 와 Servlet/JSP 버전
Spring WebMVC 5.x 까지는 JavaEE 8 을 사용해야 한다.
Spring WebMVC 6.x 부터는 Jakarta EE 9 를 사용해야 한다.
Spring WebMVC 를 사용할 때 이점
개발자가 App. 제작하고 여기서 Servlet 4.0, JSP 2.3, ... 을 사용한다.
버전 업그레이드하여 Servlet 6.0, JSP 3.1, ... 를 App. 이 사용하면 개발자는 App. 제작시 기술 규격 변화에 맞춰 migration(이전) 해야 한다.
기술 변경으로 Jakarta 를 App. 이 사용하면 개발자는 App. 제작시 기술 변경에 맞춰 전체 코드를 재작성 해야한다.
Spring Framework 가 Servlet 4.0, JSP 2.3, ... 를 사용하면 App. 이 해당 Spring Framework 를 사용하도록 개발자가 App. 을 제작해야 한다.
Spring Framework 버전 업그레이드로 Servlet 6.0, JSP 3.1, ... 사용 하면 App. 이 해당 Spring Framework 사용하도록 개발자가 App. 을 제작하는데, 기술 변경이 미미하다. 왜? Spring 이 중간에서 Adapter(완충) 역할을 수행
Spring Framework 버전 업그레이드로 Jakarta 를 사용하면 App. 이 해당 Spring Framework 를 사용하도록 개발자가 App. 을 제작하는데 기능 변경이 적다.
개발자가 App. 을 제작한다. App. 이 Spring Framework 를 사용한다. 여기서 Servlet, JSP, ... 를 사용한다.
- 개발자는 Servlet/JSP 라는 특정 기술에 종속될 필요가 없다.
- Spring 이 Servlet/JSP 기술을 캡슐화시켜서 개발자가 특정 기술에 종속되지 않도록 만든다.
Spring WebMVC 를 잘 사용하는 방법
PageController 가 Servlet API 를 사용한다. 여기서 변경이 일어나면 API 변경에 맞춰 페이지 컨트롤러를 변경해야 한다. 가능한 Servlet API 대신 Spring 이 제공하는 API 를 사용하라! 그러면 Servlet API 변경에 영향을 덜 받을 것이다!
build.gradle 에서 개발시 web 버전 설정 할 수 있다.
// 'eclipse' 플러그인 설정:
eclipse {
// 자바 웹 개발 도구에서 사용할 값을 설정한다.
wtp {
facet {
facet name: 'jst.web', version: '4.0
myapp-server/.settings/org.eclipse.wst.common.project.facet.core.xml 에 버전 나온다.
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="jst.java"/>
<fixed facet="jst.web"/>
<installed facet="jst.web" version="2.4"/>
<installed facet="jst.java" version="17"/>
<installed facet="jst.web" version="4.0"/>
</faceted-project>
조언
*
과제
학습
- com.eomcs.ioc
- com.eomcs.spring.ioc
'네이버클라우드 AIaaS 개발자 양성과정 1기 > Spring Framework, Spring Boot' 카테고리의 다른 글
[비트캠프] 83일차(18주차1일) - Spring Framework(Thymeleaf), myapp-62 (0) | 2023.03.06 |
---|---|
[비트캠프] 82일차(17주차4일) - Spring Framework(Spring WebMVC 아키텍처, Tiles), myapp-60-3, 61, 프로젝트 절차(전체 과정) (0) | 2023.03.03 |
[Java] 예제 소스 정리 - Spring WebMVC (0) | 2023.03.03 |
[비트캠프] 81일차(17주차3일) - Spring Framework: myapp-60-1, 2 (0) | 2023.03.02 |
[Java] 예제 소스 정리 - Spring IoC (0) | 2023.03.01 |