bootstrap (2)

Eclipse + SpringBoot + JSP 개발환경 세팅하기 2탄입니다.

오늘은 backend 보다는 frontend 작업을 위한 Bootstrap 추가를 webjar를 이용할 수 있도록 설정해보도록 할 예정입니다.

저는 backend 개발자다보니 front쪽은 자세히 알려드리기는 힘들지만 빠르게 서치해서 사용해본 경험상 webjar는 maven 의존성 관리를 통해 라이브러리를 다운받아 사용할 수 있어 매우 쉽게 라이브러리 추가가 가능합니다. org.webjars에는 bootstrap, jquery, font-awesome, swagger-ui 뿐만 아니라 angularJS, momentJS, d3js 등 매우 많은 프론트 개발을 위한 라이브러리들을 제공하고 있습니다. 매번 다운로드받아서 프로젝트에 추가할 필요 없이 백엔드 라이브러리들을 관리하듯이 메이븐 의존성으로 쉽게 관리할 수 있도록 도와주는 역할을 한다고 보시면 됩니다.

우선 지난시간에 했던 Eclipse + SpringBoot + JSP 개발환경 세팅하기 1탄 을 완성하셨던 분들을 기준으로 설명을 할 예정이니 해당 포스팅을 안보신 분들은 한번 쭈욱~ 훑어보시고 다시 오시기 바랍니다.

webjar 설정을 위해서 추가할 파일은 딱 하나입니다. org.springframework.web.servlet.config.annotation.WebMvcConfigurer를 구현하는 WebMVCConfig 클래스를 하나 생성하고 다음과 같이 addResourceHandlers 메서드를 오버라이드하여 작성해줍니다.

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
	    if (!registry.hasMappingForPattern("/webjars/**")) {
	        registry.addResourceHandler("/webjars/**").addResourceLocations(
	                "classpath:/META-INF/resources/webjars/");
	    }
	    if (!registry.hasMappingForPattern("/**")) {
	        registry.addResourceHandler("/**").addResourceLocations(
	        		new String[] {"classpath:/static/script", "classpath:/static/style"});
	    }
    }

 

우선 webjars 경로를 등록해주는 것 때문에 이 클래스를 만들어 사용하는데 이때 @EnableWebMvc 어노테이션을 사용하게 됩니다. 그런데 여기서 주의할 점이 이 어노테이션을 사용하게되면 WebMvcAutoConfiguration 이 disable되면서 기존 설정들이 정상적으로 동작하지 않게 됩니다. 따라서 기존에 잘 읽어오던 static하위의 javascript파일들과 css파일들을 못찾아 404 오류가 발생하게 되죠. 그래서 addResourceHandlers에 이 두 파일들이 존재하는 디렉토리를 classpath경로로 추가해줘야 합니다.

또한, application.properties 파일에 작성하였던 아래 두 라인은 더이상 사용하지 않고 방금 추가한 WebMVCConfig 클래스에 별도로 ViewResolver를 등록하여 사용해야합니다.

	@Bean
	public ViewResolver getViewResolver(){
	    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
	    resolver.setPrefix("/WEB-INF/views/");
	    resolver.setSuffix(".jsp");
	    resolver.setViewClass(JstlView.class);
	    return resolver;
	}

 

아래는 완성된 WebMVCConfig 클래스의 코드입니다.

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
public class WebMVCConfig implements WebMvcConfigurer {

	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
		if (!registry.hasMappingForPattern("/webjars/**")) {
	        registry.addResourceHandler("/webjars/**").addResourceLocations(
	                "classpath:/META-INF/resources/webjars/");
	    }
	    if (!registry.hasMappingForPattern("/**")) {
	        registry.addResourceHandler("/**").addResourceLocations(
	        		new String[] {"classpath:/static/script", "classpath:/static/style"});
	    }
    }
	
	@Bean
	public ViewResolver getViewResolver(){
	    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
	    resolver.setPrefix("/WEB-INF/views/");
	    resolver.setSuffix(".jsp");
	    resolver.setViewClass(JstlView.class);
	    return resolver;
	}
}

 

자, 모든 준비는 완료가 되었습니다. 이제 pom.xml에 다음과 같이 부트스트랩 의존성을 추가해줍니다.

		<!-- Bootstrap CSS -->
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>4.5.0</version>
		</dependency>

 

그리고 test.jsp 파일을 열어 아래와 같이 부트스트랩을 링크걸어줍니다.

<link rel="stylesheet" href="/webjars/bootstrap/4.5.0/css/bootstrap.min.css" />

 

만약 부트스트랩이 아닌 jQuery와 같은 javascript 라이브러리를 사용하고자 할 경우 의존성 추가는 동일하게, jsp파일에 링크를 걸어줄 때에는 아래와 같은 형태로 해주시면 됩니다.

<script src="/webjars/jqeury/3.5.1/js/jqeury.min.js"></script>

 

자, 여기까지 완료되면 모든 준비는 끝난것입니다. 이제 부트스트랩에서 제공하는 기능을 마음껏 사용하시면 됩니다.

저는 지난 시간에 최종결과물에서 버튼을 하나 추가해보는 정도로 이번 포스팅을 마치겠습니다.

test.jsp의 body에 다음 한 줄을 추가했습니다.

<button type="button" class="btn btn-danger btn-lg">버튼</button>

 

그리고 결과를 확인해보면 아래와 같이 빨간색 버튼이 추가된 것을 확인할 수 있습니다.

 

이상으로 Eclipse + SpringBoot + JSP 개발환경 세팅하기 2탄 포스팅을 마칩니다.

오늘도 즐겁고 행복한 코딩을 하는 케이치였습니다~

💻 Programming/Java

JVM 클래스로더란? ( What is ClassLoader ? )

1. 개요
Cass Loader 란 abstrace class로써 Bytecode를 읽어 들여서 class 객체를 생성하는
역활을 담당한다.

Class Loader가 Class를 Loading하는 시점은 ComplieTime이 아닌 Run Time에 Loading이 된다.

프로그래머 가 SampleTest aaa = new SampleTest(); 라는 코드를 처음 실행하면
JVM은 SampleTest라는 Class를 Class Loader를 통해서 SampleTest.clas의 ByteCode를
최초로 메모리에 Load하게 된다. 



2. ClassLoader 기술적 특징
   - Hierarchical 
     Class Loader는 Hierarchical 하게 생성이 가능하고, Parent class laoder에서, child class loader
     갖는것과 같이 Class Loader간의 계층형 구조를 갖게 된다. 최상위 Class Loader는  
     "bootstrap"   Class Loader가 위치 하게 된다.

   - Delegate load request
      Class loading에는 일정한 규칙이 필요하다. 이는 Class Loader가 계측형의 구조를 가지고
      있기 때문에, 어느 시점에 Class 로딩 요청을 받으면 상위 Class Loader가 Loding한 Class가 
      우선권을 가진다. 

   - Have visibility constraint
     Child Class Loader는 Parent Class Loader의 Clss를 찾을수 있지만, 그 반대의 경우는 불가능하다.

   - Cannot unload classes
      Class Loader에 의해서 Loading된 Class들은 unload 될수가 없다.



3. Class Loader 위임
   -

옆의 그림은 class loader delegation model 이다.
     이는 Loading요청을 서로 에게
     전달 하는 ClassLoader의 그래프
     이다. 

     옆의 그림과 같이 Class Loader
     들은 하나의 delegation parent
     함께생성되고 다음 위치 에서
     Class를 찾는다.

     * 다음 위치란
      Cache, Parent, Self

    CalssLoader가 최초 하는 일은
    전에도 같은 Class를 Loading
    하도록 요청을 받았는지를
    먼저 파악한다.

    만약 요청을 받은적이 있으면,
    Cache에 저장된 Class를
    리턴 한다.

    그렇지 않을 경우,
    Parent Class를 Loading 할
    기회를 준다.

    이러한 두 단계들이 반복되고 Depth First 방식으로 탐색이 진행 된다.

    만약 Parent Class에도 해당 Class가 존재하지 않으면 (ClassNotFoundException)
    ClassLoader는 Class의 소스에 대한 공유(작업한 코드)의 경로 (Self)를 검색한다.

    Parent ClassLoader는 Class를 처음으로 loading할 기회가 주어지기 때문에 Root에
    가장 가까운 ClassLoader에 의해 로딩 된다.

   가장 핵심적인 bootstrap class들은 java.lang.Object같은 정확한 클래스 버전이 로딩되었는지
   확인하고, Class Loader가 그 자체 또는 부모(Parent)에 의해서 Loading 되었는지
   Class가 불 수 있도록 한다. 위에서 말했다 싶이 자식에 의해 Loading된 Class 들은 볼 수 없다. 


   - Bootstrap Class Loader
   다른 ClassLoader들과는 달리 Bootstrap Class Loader 는 자바 코드에 의해서
   instance화 될 수 없다
   Bootstrap ClassLoader 는 Boot ClassPath에서 핵심 시스템 Class들을 로딩하는데
   이것은 일반적으로 JavaHome의 jre/lib 디렉토리에 있는 JAR 파일들이다.
   단 -Xbootclasspath 옵션으로 classpath를 추가 수정할 수 있다.


   - Extension Class Loader
   주로 jre/lib/ext 디렉토리에 위치한 Extension 디렉토리에서 Class 들을 Loading 한다. 
   사용자의 classpath를 수정하지 않고 다양한 보안 확장 같은 새로운 확자으로 쉽게
   갈 수 있는 기능을 제공 한다.

   - System Class Loader 
   CLASSPATH 환경 변수에 지정된 결로에서 코드를 로딩 한다. 
   기본적으로 이 Class Loader는 사용자가 생성한 모든 ClassLoader의 Parent 이다. 


  
4. Class Loding 단계 
   - Class Loadig은 Loading, Linking, initialzing 단계로 나누어 진다.

   - 대부분의 Class Loading과 관련된 문제는 이 세단계 중 한 단계에서 발생한다.

   - 로딩 단계는 필요한 Class File을 배치하고 ByteCode로 Loading하는 단계 이다.

   - JVM의 로딩 프로세스는 Class 객체에 매우 기본적인 메모리 구조를 제공한다.
     메소드, 필드, 기타 참조 Class 들이 이 단계에서는 다루어지지 않는다.

 
   - Linking은 세 단계 중에서 가장 복잡한 단계이다. 다름과 같이 세 개의 주요 단계들로 나뉜다. 
     ㄱ. ByteCode 확인 - ByteCode가 정상적으로 작동 하는지 확인 한다. 
     ㄴ. Class Preparation - Class 에서 정의된 필드, 메소드, 인터페잇 들을 나타내는 
                                       데이터 구조를 준비한다. 
     ㄷ. Resolving - Class 에 다양한 방식으로 참조된 모든 Class들을 Loading한다. 
                         - super class, interface, fild, method signature, local fild

   - initialize 단계 동안, Class 내에 포함된 정적 initializer들이 실행된다. 이 단계의 끝에 가서는 
     기본 값으로 초기화 된다. 

   - 이 세 단계를 지나면 Class는 완전히 로딩되고 사용할 준비가 된다. 
     Class Loading은 Lazy방식으로 수행 될 수 있기 때문에 일부 Class Loading Processor 는 
     Loading 시점외에 처음 클래스를 사용할 때 수행될 수도 있다.   


5. Explicit Loading vs Implicit Loading
   - 클래스가 로딩되는 두가지 방식의 차이
   - Explicit : 다음과 같은 메소드 호출들 중 하나를 사용하여 로딩될 때 발생한다.
                  - (java.lang.ClassLoader).loadClass()
                  - Class.forName()
   - 이러한 메소드들 중 하나가 호출 되면 이름이 인자로 지정된 클래스가 클래스 로더에 의해서
     로딩
된다. 
     그렇지 않을 경우, 로더는 클래스를 로딩하기 위해 delegation model을 사용한다.
 
   - Implicit : Class 가 레퍼런스, 인스턴스화, 명시적 메소드 호출을 제외한 상속의 경우 로딩되는 방식
                   경우 슬그머니 로딩작업은 초기화되고 JVM은 필요한 레퍼런스를 결정하여
                   만약 로딩이 되어 있으면 레퍼런스만 리턴되고 그렇지 않을 경우 델리게이션 모델을
                   사용하여 클래스를 로딩하게 된다. 

   


참고 자료:
http://www.ibm.com/developerworks/java/library/j-dclp1/index.html?S_TACT=105AGX02&S_CMP=EDU
및 인터넷 문서



출처 : http://liebus.tistory.com/30