본문 바로가기

Programing/JVM(Java, Kotlin)

Spring Framework - Quick Start

2019년 1월 시점 아래 글은 이제 오래된 글입니다.

https://start.spring.io/ 스프링 Initializer를 이용해보세요.


-----


스터디 소스 출처: http://projects.spring.io/spring-framework/


환경

자바환경: Java 1.7.0_45

개발환경: Eclipse Java EE IDE for Web Developers. (Kepler Service Release 1 ; 4.3)

스프링환경: STS를 사용하지 않고 Spring IDE를 설치하여 사용

( http://spring.io/tools/sts/all 에 있는 Update Sites http://dist.springsource.com/release/TOOLS/update/e4.3/ 를 이용)


소스코드 : IoC에 대한 이해를 위해 만들어진 것 같음


이클립스 프로젝트 생성하기

원래 Gradle로 하려고 했는데 STS 툴 자체가 Maven 기반으로 되어 있다보니 우선은 있는 데로 하기로 했다.


New > Projet > Spring > Spring Starter Project : 선택하고 'Next' 버튼.


New Spring Starter Project : 아래 빨간색을 채워넣고 'Finish'버튼.


기본적으로 src/main/java/hello와 src/test/java/hello 아래 java 파일이 있는데 지운다.


pom.xml 파일을 열어 모두 지운다.



QuickStart에 보면 Maven 정보가 있다.


이 정보를 바탕으로 의존 속성(Dependency Property) 추가를 해준다.



이제 http://projects.spring.io/spring-framework/#quick-start 에 있는대로 소스코드를 만들어 본다.


프로그래머 인생이 녹녹치 않듯 실행을 하면 아래와 같이 에러가 난다. 또한 ApplicationContext context 부분에는 경고도 있다.


commons-logging 의존성

 의존성을 끊어주기 위한 프레임워크가 다른 라이브러리에 의존을 하고 있다니, 좀 아이러니 하긴한데,, 사실 스프링이 없애려고 하는 의존성은 애플리케이션에 대한 것이니 논외로 하고...


Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

at org.springframework.context.support.AbstractApplicationContext.<init>(AbstractApplicationContext.java:153)

at org.springframework.context.support.GenericApplicationContext.<init>(GenericApplicationContext.java:100)

at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:60)

at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:82)

at hello.Application.main(Application.java:22)

Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory

at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

at java.security.AccessController.doPrivileged(Native Method)

at java.net.URLClassLoader.findClass(URLClassLoader.java:190)

at java.lang.ClassLoader.loadClass(ClassLoader.java:306)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)

at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

... 5 more


에러를 따라 StackTrace 해보면 AbstractApplicationContext가 범인이다.


스프링 프레임워크가 의존하는 다른 라이브러리가 있다니...

Maven (pom.xml)에 commons-logging 에 대한 의존성을 추가해 준다.

정보는 http://mvnrepository.com/artifact/commons-logging/commons-logging 를 참고한다.


다시 실행해보면... Hello World가 찍힌다.

거슬리는 Warning

한가지 거슬리는 것은 앞서 언급한 Warning이다.


quick fixes가 추천해준 @SuppressWarnings를 붙이고 싶은 욕구가 불끈불끈 솟는다.

이클립스가 경고를 띄어주는 이유는 AnnotationConfigApplicationContext가 (사실 부모..부모...가) Closeable를 상속받았기 때문이다.

관련 사항은 Eclipse documentation를 참고하면 알 수 있다.

자바 1.5의 java.io.Closeable 인터페이스나 자바 1.7의 java.lang.AutoCloseable 인터페이스를 구현한 클래스들을 close()를 호출하지 않으면 리소스 누수가 발생할 수 있기에 경고를 해주는 것이라고 한다. (요약은 여기서)


그런데 ApplicationContext에는 눈을 씻고 찾아봐도 close() 메소드가 없다. 원인 제공자인 AnnotationConfigApplicationContext 때문에 발생하는 것을 ApplicationContext에 왜 없냐고 묻는 것은 우물가에서 숭늉찾는 격인 것이다. 클래스의 계층을 살펴보면 아래와 같다.

class AnnotationConfigApplicationContext extends GenericApplicationContext

class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry

abstract

class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {

// ...

        @Override

        public void close() {

               synchronized (this.startupShutdownMonitor) {

                       doClose();

                       // If we registered a JVM shutdown hook, we don't need it anymore now:

                       // We've already explicitly closed the context.

                       if (this.shutdownHook != null) {

                              try {

Runtime.getRuntime().removeShutdownHook(this.shutdownHook);

                              }

                              catch (IllegalStateException ex) {

                                      // ignore - VM is already shutting down

                              }

                       }

               }

        }

// ...

}

interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable

보면 AbstractApplicationContext에서 close를 구현하고 있다. 또한 Closeable를 상속한 직계 인터페이스는 ConfigurableApplicationContext라는 것도 알 수 있다. (이놈이 원인이여.. 이클립스는 참 대단해. 이런 것을 참 빨리도 찾네)


다시 원래대로 돌아가서...

ApplicationContext를 ConfigurableApplicationContext로 다운캐스팅을 하면 close()가 가능해진다. (출처)


수행을 해보면 "Hello World!" 아래에 doClose가 호출되는 빨간색 메세지가 추가되었음을 알 수 있다.


최종 소스는 => SpringFrameworkQuickStart.zip  (다행히 10M가 안되어서...)

  1. Don't Repeat Yourself [본문으로]