Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
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
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[비트캠프] 80일차(17주차2일) - Spring Framework(Spring IoC 컨테이너) 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/Spring Framework, Spring Boot

[비트캠프] 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