Spring/Spring 이야기

[Spring framework] 공부를 해보자 1탄

seungdols 2016. 7. 18. 22:19

Spring framework

Spring내에서 가장 기초적이고 가장 중요한 두개의 패키지는 org.springframework.beansorg.springframework.context패키지이다. 이 패키지내 코드는 Spring의 Inversion of Control(대안으로 Dependency Injection으로 불리는)기능의 기초를 제공한다. BeanFactory는 잠재적으로 어떤 종류의 저장 기능을 사용하여 어떤 성질의 bean을 관리하는 향상된 설정 기법을 제공한다.

ApplicationContextBeanFactory(또는 하위클래스)의 가장 상위에 위치하고, 향상된 점 중에서 Spring AOP기능의 좀더 쉬운 통합, 메시지 자원 핸들링(국제화내에서 사용하기 위한), 이벤트 위임, ApplicationContext와 옵션적으로 부모 컨텍스트를 생성하기 위한 선언적인 기법, WebApplicationContext와 같은 애플리케이션 레이어 특정 컨텍스트를 사용하는 것과 같은 다른 기능을 추가한다.

ApplicationContext를 사용하는 것이 좋다. BeanFactory의 모든 기능을 포함하고 있다. (몇 가지 상황을 제외하고서는 좋은 선택이다.)

기본 BeanFactory를 사용할 경우 트랜잭션, AOP 같은 많은 기능을 개발자가 만들어 줘야 한다.(힘들껄..?)

@RequestMapping관련 글은 링크를 참조하면 된다.


DispatcherServlet

스프링 웹 MVC 프레임워크는 요청 중심 즉, 중앙에서 모든 요청을 받은 뒤, 각각 역할에 맞는 기능을 분산 시키게 된다.
중앙 서블릿 중심으로 설계되어 있어 웹 어플리케이션을 개발하는 데 기능들을 제공한다. 또한, DispatcherServlet스프링 IoC 컨테이너와 완전히 통합되어 있어서 스프링이 가진 모든 다른 기능을 사용할 수 있다. (즉, IoC 컨테이너가 디스패처의 기능을 일임 받을 수 있다는 것으로 볼 수 있지 않을까 … ?)

DispatcherServlet img

DispatcherServlet은 실제로도 Servlet이며, HttpServlet 기반 클래스를 상속 받는다. web.xml 파일에 선언 되어 있다.(없으면 안...)

<web-app>
  <servlet>
  <servlet-name>example</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
  <servlet-name>example</servlet-name>
  <url-pattern>/example/*</url-pattern>
  </servlet-mapping>
</web-app>

스프링 웹 MVC의 컨텍스트 계층

WebApplicationContextApplicationContext의 확장이며, 웹 어플리케이션이 필요로 하는 기능을 추가한 것이다.

xx-servlet.xml에서 설정 하는 것들이 몇 가지가 기본적으로 존재한다.

<context:component-scan base-package="com.seungdols.web" />

위는 사용할 빈들을 자동적으로 스캔하여 빈으로 등록을 해준다.

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>

위는 view에 대한 설정을 하는 것인데, prefix는 jsp 파일들의 경로를 지정하는 것을 뜻하고, suffix는 파일들의 확장자를 .jsp로 지정한다.

특히, InternalResourceViewResolver의 경우에는 prefix, suffix 이들을 이용해 나중에 컨트롤러에서 리턴받은 view name을 prefix + name + suffix를 붙여 view를 찾게 된다.

<mvc:resources mapping="/resources/**" location="/resources/" />

위 설정은 스크립트, 이미지, 파일들의 경로를 결정하는 것이다.


<mvc:annotation-driven />

<mvc:annotation-driven>

  1. DefaultAnnotationHandlerMapping
    • @RequestMapping을 이용한 핸들러 매핑 전략 등록, 가장 우선된다.
  2. AnnotationMethodHandlerAdapter
    • 디폴트 핸들러 어댑터
  3. ConfigurableWebBidingIntializer
  4. Message Converter
  5. <spring:eval>을 위한 컨버젼 서비스 노출용 인터셉터
  6. Validator
  7. Conversion-service

Logging

log를 사용하여 문제점을 찾는데 쉽게 활용 할 수 있고, 중요한 정보로 활용 할 수 있기에 로그는 중요하다.

그 중에서 다양한 Logging framework가 존재하는데, 이를 입맛대로 설정 할 수 있게끔 사용하고 싶다면, SLF4J를 사용하면 된다. 이는 로깅 퍼사드로 로깅에 대한 추상화만 제공하며, 구현체를 어떤 로깅 프레임워크를 사용해도 무방합니다.

사실 이 중에서 가장 많이 사용했던 것은 log4j지만, log4j의 단점들을 개선 시킨 Logback이 그 자리를 교체해가고 있다.

즉, SLF4J는 추상화 (Interface만 제공) Logback은 해당 SLF4J를 그대로 구현한 것이라 이해 하면 됩니다.

Maven에서 사용하기 위해서는 pom.xml에 다음을 추가를 하면 된다.

<dependency>
<groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
  <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>${org.slf4j.version}</version>
  </dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>

</dependency>

또한, spring-context가 JCL을 사용하는데, 그냥 두면, commons-logging이 의존성이 자동으로 추가가 되어 있어 문제가 되니 제거를 해야 한다.

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
  <exclusions>
  <exclusion>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  </exclusion>
  </exclusions>
</dependency>

그리고 사용 하기 위해서는 src/main/resources/하위에 logback.xml 파일이 필요합니다.
단, logback은 파일의 우선순위가 존재합니다.

  1. logback.groovy
  2. logback-test.xml
  3. logback.xml
  4. Basic config

위와 같은 순서로 파일을 찾아 해당 파일의 내용을 설정합니다.

간단 설정

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  <layout class="ch.qos.logback.classic.PatternLayout">
  <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
  </layout>
  </appender>
  <logger name="com.seungdols.web" level="DEBUG"/>
  <root level="debug">
  <appender-ref ref="STDOUT" />
  </root>
</configuration>

사용

static final Logger logger = LoggerFactory.getLogger(BoardController.class);

static final로 선언해야 하며, transient를 쓰면 NullPointerException(비싼 에러)을 발생 시킨다.

@RequestMapping(value = {"/", "/hello"}, method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
logger.debug("Home Page");
model.addAttribute("message", "Spring 3 MVC Hello World");
return "hello";

}

결과

18:02:05.574 [http-apr-8080-exec-3] DEBUG c.s.web.controller.BoardController - Home Page

참고 LogBack.xml 설정 변경사항

<layout class="ch.qos.logback.classic.PatternLayout">

위에서 ch.qos.logback.classic.PatternLayoutDeprecated 되었다.

그래서 변경해야 한다.

<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">


반응형