반응형
스프링(Spring) - 사전설정
메이븐 라이브러리 최신버전으로 빌드처리 하기
- 프로젝트의 [pom.xml] 파일을 변경하여 Maven Dependencies 라이브러리의 빌드 변경
- Maven : 빌드 툴(Build Tool)
→ 프로그램의 라이브러리를 관리하기 위한 프로그램(빌드 툴) - pom.xml : 메이븐을 사용해 프로젝트의 라이브러리를 빌드 처리하기 위한 정보를 제공하는 환경설정 파일
→ 로컬 저장소(git 말고 메이븐 로컬 저장소를 말한다.)에 저장된 라이브러리 파일을 제공받아 프로젝트에 빌드 처리
→ 로컬 저장소에 라이브러리 파이링 없는 경우 메이븐 저장소에서 라이브러리 파일을 다운로드 받아 로컬 저장소에 저장하여 사용
(필요한 라이브러리를 빌드처리해달라고 메이븐한테 요청하면, 메이븐이 로컬저장소를 찾아 있으면 빌드처리 해주고, 없으면 알아서 다운로드 처리해서 로컬 저장소에 저장해서 빌드처리 해준다 ⇒ 즉, 알아서 해준다는 거다.) - 메이븐 로컬 저장소(Local Repository) : 프로젝트에 빌드될 라이브러리 파일이 저장된 폴더
→ 기본적으로 사용자 폴더의 [.m2] 폴더를 로컬 저장소로 사용한다.
→ 라이브러리 파일에 문제가 있어 프로그램 실행시 에러가 발생될 경우 이클립스 종료 후 해당 라이브러리 파일(폴더)을 삭제하고 이클립스를 재실행한다.(그럼 pom.xml 파일을 다시 읽어들인다.)
→ 만약 어디가 문제인지 도저히 모르겠을때는 [.m2] 폴더 안에 [repository]폴더를 다 지워도 된다.
- 메이븐 저장소(Maven Repository) : 라이브러리 파일이 저장된 인터넷의 저장소
→ https://mvnrepository.com
→ 이 사이트에서 필요한 라이브러리 검색을 하고 pom.xml에 해당 라이브러리에 대한 코드를 붙여넣으면 된다. - 현재 작업중인 프로젝트를 메이븐으로 배포하기 위한 파일을 생성할 때 필요한 정보를 제공하는 엘리먼트
- properties : pom.xml 파일에서 자주 사용하는 값을 이름으로 제공하기 위한 엘리먼트
→ 하위 엘리먼트명을 식별자로 사용하여 엘리먼트 내용을 값으로 제공한다.
→ pom.xml 파일에서 ${이름} 형식으로 표현하여 값을 제공받아 사용
→ (얘를 쓰는 이유는) 라이브러리 버전을 효율적으로 관리하기 위해 사용한다. - page-context 다운
→ 6대버전은 JDK17을 기반으로 만들어졌는데, 레거시 프로젝트는 JDK 11을 기반으로 하기 때문에 우리는 5점대 버전으로 써야 한다. - dependencies : dependency 엘리먼트를 등록하기 위한 엘리먼트
- dependency : 라이브러리 파일을 제공받아 프로젝트에 빌드 처리하기 위한 엘리먼트
→ 라이브러리 의존 관계에 의해 필요한 라이브러리를 프로젝트에 자동으로 빌드 처리(그래서 최소한의 라이브러리만 빌드처리 해주면 된다.)
→ 의존 전이(Transitive Dependencies) - Spring : Spring 프레임워크 기능을 제공하기 위한 라이브러리
- groupId : 라이브러리 파일을 제공하는 그룹의 도메인을 설정하기 위한 엘리먼트
- artifactId : 라이브러리의 이름을 설정하기 위한 엘리먼트
- version : 라이브러리의 버전을 설정하기 위한 엘리먼트
- groupId 안에 있고, version에 해당하는 artifactId 이름의 라이브러리를 빌드처리 해달라는 의미
- exclusions : exclusion 엘리먼트를 등록하기 위한 엘리먼트
- exclusion : 의존 관계의 라이브러리 중 제외 라이브러리를 설정하기 위한 엘리먼트
- AspectJ : Spring AOP 기능을 제공하기 위한 라이브러리
- scope : 프로젝트에 라이브러리가 빌드되는 시점을 설정하는 라이브러리
→ <scope>runtime</scope> 추가(프로그램 실행할 때 빌드처리)
- 참고로 회색으로 어둡게 표시된 라이브러리들은 scope에 의해 실행되는 시점이 다르고 아직 빌드된 상태가 아니라서 어두운 색깔로 표시되어있다.
- Logging : 로깅(Logging) 관련 기능을 제공하기 위한 라이브러리
(기록 뿐만 아니라 로그 이벤트를 발생시키는 클래스도 있다)
- log4j
- @Inject : @Inject 어노테이션으로 Spring DI 구현에 필요한 기능을 제공하는 라이브러리
- Servlet
→ 버전 변경
- servlet API와 JSP API 는 버전만 바꾸는게 아니라 라이브러리에서 제공하는 코드 전체로 바꾼다.
- JUnit 버전 변경
경로에 한글이 있어서 로그구현체 로깅이 안되는 경우
- xercesImpl (https://mvnrepository.com/artifact/xerces/xercesImpl)
→ 로그 구현체가 로깅정보를 기록할 때 인식할 수 없는 문자가 존재할 경우 에러 발생
→ 로깅정보에 인식할 수 없는 문자가 존재할 경우 부호화 처리하는 기능을 제공하는 라이브러리
로그 구현체 설정하는 방법
- log4j.xml : 로그 구현체 실행에 필요한 정보를 제공하기 위한 환경설정파일
→ 로그 구현체 : 로그 팩토리로부터 발생된 로깅정보를 제공받아 기록하기 위한 프로그램 - appender : 로그 구현체를 설정하기 위한 엘리먼트
- name 속성 : 로그 구현체(appender 엘리먼트)를 구분하기 위한 식별자를 속성값으로 설정
- class 속성 : 로그 구현체로 실행하기 위한 클래스를 속성값으로 설정
→ http://logging.apache.org/log4j/1.2/apidocs 사이트 참조
→ class 속성값으로 설정될 클래스는 반드시 Appender 인터페이스를 상속받은 클래스로만 설정
→ ConsoleAppender 클래스 : 로그정보를 제공받아 콘솔에 기록하기 위한 클래스 - param 엘리먼트 : Appender 클래스에 필요한 값을 제공하기 위한 엘리먼트(무엇을 기록할 것인가를 설정)
→ Appender 클래스마다 name 속성값과 value 속성값을 다르게 설정하여 사용 - layout 엘리먼트 : 로깅정보를 제공받아 기록하기 위한 패턴을 설정하기 위한 엘리먼트(어떻게 기록할것인가를 설정)
- class 속성 : 기록 관련 패턴에 대한 정보를 제공하기 위한 클래스를 속성값으로 설정
→ PatternLayout 클래스 : 패턴문자 관련 정보를 제공하기 위한 클래스
- 변환문자(Conversion Character) : 변환문자는 일반문자와 구분하기 위해 % 기호로 시작
- %c : 로그 이벤트가 발생된 카테고리 이름(패키지가 포함된 클래스)을 기록 - {정수값}을 이용하여 원하는 형식의 이름으로 기록 가능
→ ex) %c{1} : 패키지를 제외한 클래스의 이름을 기록
%c{1} : (xyz.itwill.spring.Test ⇒ Test)
%c{2} : (xyz.itwill.spring.Test ⇒ spring.Test)
%c{3} : (xyz.itwill.spring.Test ⇒ itwill.spring.Test) - %C : 로그 이벤트가 발생된 클래스 이름(패키지 포함)을 기록
- %d : 로그 이벤트가 발생된 날짜와 시간을 기록 - {SimpleDateFormat}을 허용해 원하는 형식으로 기록
→ ex) %d{yyyy-MM-dd} : [년-월-일] 형식으로 기록 - %m : 로그 이벤트에 의해 전달된 로그 메세지를 기록
- %n : 엔터(Enter)를 기록
- %M : 로그 이벤트가 발생된 메소드의 이름을 기록
- %p : 로깅 정보를 제공한 로그 이벤트를 기록
→ 로그 이벤트 : TRACE(최하위) >> DEBUG >> INFO >> WARN >> ERROR >> FATAL(최상위) - %t : 로그 이벤트를 발생한 스레드의 이름을 기록
- %r : 프로그램 시작 이후부터 로깅 정보를 제공받아 기록되는 시간(ms)을 기록
- logger : 특정 패키지의 클래스에서 발생되는 로그 이벤트를 기록하기 위한 엘리먼트
→ logger 엘리먼트는 root 엘리먼트에 설정된 로그 구현체(Appender)를 제공받아 사용 - name 속성 : 로그 이벤트가 발생될 클래스의 패키지를 속성값으로 설정
- value 속성 : 로그 이벤트를 속성값으로 설정
- level : 클래스에 적용될 로그 이벤트를 설정하기 위한 엘리먼트
→ root 엘리먼트의 priority 엘리먼트로 제공되는 로그 이벤트보다 우선 처리 - root : 모든 클래스에서 발생되는 로그 이벤트를 기록하기 위한 엘리먼트
→ logger 엘리먼트는 기본적으로 root 엘리먼트의 정보를 제공받아 사용 - priority : 모든 클래스에 적용될 로그 이벤트를 설정하기 위한 엘리먼트
- value 속성 : 로그 이벤트를 속성값으로 설정
→ 속성값으로 설정된 로그 이벤트보다 상위 로그 이벤트가 발생된 경우에도 로깅정보 기록 - appender-ref : 로깅정보를 제공받아 기록하기 위한 로그 구현체(Appender)를 설정하는 엘리먼트
- ref 속성 : appender 엘리먼트의 식별자를 속성값으로 설정
로그 구현체로 이벤트 발생시키기
- xyz.itwill00.log(패키지) // HelloWorld(클래스) // HelloWorldApp(클래스) // LogHelloWorld(클래스) // LogHelloWorldApp
- 로그구현체를 이용하지 않아도 기록은 할 수 있다(아래와 같은 방법으로)
- 이 예제는 웹프로그램 아니니까 그냥 java application으로 실행한다
- 그런데 단점은, 기록하는 명령과 실제 데이터 출력 명령이 같은 스레드에 있다보니 기록 명령 때문에 처리가 느릴 수 있다.
그리고 기록 명령을 일일히 적어줘야 하는 부분 때문에 불편함이 있다.
⇒ 그래서 로그 구현체가 필요한거다. 명령실행 스레드와 다른 스레드를 쓰고 기록도 해준다. - 로그 구현체는 왜 필요한지? 로그 구현체로 로깅정보를 어떻게 기록할지 알아야 한다.
- HelloWorld(클래스) // HelloWorldApp(클래스) ⇒ 로그 구현체 사용 안하고 로그 기록
- LogHelloWorld(클래스) // LogHelloWorldApp ⇒ 로그 구현체를 사용하여 로그 기록
- 로그 이벤트 발생 >> 로그 이벤트를 발생하려면 로그라는 객체가 있어야 한다.
- Logger 객체 : 로그 이벤트를 발생하기 위한 객체
→ Logger 객체에 의해 로그 이벤트가 발생되면 로그 구현체가 로그 이벤트에 대한 로깅정보를 제공받아 기록
- 누구나 사용하면서 바뀌지 말라고 상수필드를 사용한다.
- LoggerFactory 클래스 : Logger 객체를 생성하여 제공하기 위한 클래스 - Factory 클래스
- LoggerFactory.getLogger(Class<T> class) : 매개변수에 Class 객체를 전달하여 해당 클래스에서 로그 이벤트를 발생할 수 있는 Logger 객체를 생성하여 반환하는 정적 메소드
→ 다른 클래스에서는 이 로거 못쓴다.
- Logger.info(String message) : Logger 객체로 INFO 레벨의 로그 이벤트를 발생하는 메소드
→ 매개변수에는 로그 구현체로 기록될 로그 메세지 전달 - 로그 구현체가 사용되는 스레드가 따로 있어서 그 스레드를 가지고 로깅정보를 기록한다.
- 로그구현체로 이벤트를 발생시켰는데 기록이 안된다.
그 이유는 info 레벨의 구현체는 로그 구현체가 기록하지 않기 때문이다.
왜냐하면 설정에서 warn 레벨 이상을 기록하라고 설정되어있기 때문이다.
- 해결 1)
info 를 warn으로 바꾸는거다.
그런데 내가 info 레벨 이상일때 기록하고 싶다면, - 해결2)
→ log4j.xml 파일에에서 warn 설정을 info 설정으로 바꾼다 - 해결3)
→ log4j.xml 파일에 logger를 하나 더 만드는거다
<logger name="xyz.itwll00.log"> <level value="info"/> </logger> |
|
INFO : xyz.itwill00.log.LogHelloWorldApp - 시작 INFO : xyz.itwill00.log.LogHelloWorld - 시작 INFO : xyz.itwill00.log.LogHelloWorld - 종료 message = 홍길동님, 안녕하세요. INFO : xyz.itwill00.log.LogHelloWorldApp - 종료 |
- appender를 추가해서 우리가 원하는 형태로 기록되어지게 할 수 있다.
- 그런데 appender를 만들었다고 바로 그렇게 기록되지는 않는다.
root 에 콘솔 어펜더를 사용하라고 했기 때문에.
그래서 appender-ref를 써야 한다.
<appender name="hello" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%c{1} 클래스의 %{M} 메소드 호출 - %m%n" /> </layout> </appender> |
<logger name="xyz.itwill00.log"> ⇒ 이 패키지 에서 <level value="info"/> ⇒ info 레벨 이벤트 발생할때 <appender-ref ref="hello"/> ⇒ hello appender를 사용해 기록해주세요 </logger> |
- logger 엘리먼트는 root 엘리먼트에서 사용하는 로그 구현체로 로깅 정보를 기록한다.
→ logger 엘리먼트에 appender-ref 엘리먼트를 작성해 원하는 로그 구현체로 기록되도록 설정 가능하다.
→ logger 엘리먼트의 로그 구현체와 root 엘리먼트에서 제공되는 로그 구현체로 기록 - 그런데 이렇게 했을때 콘솔어펜더를 같이 사용하게 되는데, 그걸 원치 않을때 설정하는 방법이 있다.
- additivity 속성 : false 또는 true(기본값) 중 하나를 속성값으로 설정
→ additivity 속성값을 [false]로 설정하면 root 엘리먼트로 제공하되는 로그 구현체를 사용하지 않고 looger 엘리먼트의 appender-ref 엘리먼트로 제공된 로그 구현체만 사용해 기록되도록 설정할 수 있다.
<logger name="xyz.itwill00.log" additivity="false"> <level value="info"/> <appender-ref ref="hello"/> </logger> |
- 기본적으로는 root 로 제공되는 로그 구현체 쓰는데 원하면 appender를 추가해서 내가 원하는 로그 구현체를 설정할 수 있다.
- 콘솔어펜더의 단점은 기록을 나중에 확인할 수 없다는 것이다.
그래서 일반적으로 파일 어펜더를 사용하여 영구적으로 저장할 수 있다.
→ 이메일을 이용해서 전달할수도 있고, 파일로만 저장할수도 있다. - DailyRollingFileAppender : 파일에 기록하는데, 기록파일이 하루마다 바뀌게 해주는 어펜더
<appender name="daily" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="dailyLog"/> <param name="DatePattern" value=".yyyy-MM-dd"/> </appender> |
- appender-ref 는 여러개를 만들어도 된다.
<logger name="xyz.itwill00.log" additivity="false"> <level value="info"/> <appender-ref ref="hello"/> <appender-ref ref="daily"/> </logger> |
스프링(Spring) IoC(제어의 역행)
IOC
- IoC(Inversion Of Control) : 제어의 역행
- IoC의 개념을 적용함으로 인해 얻을 수 있는 장점 : Container 기능을 제공하여 객체간의 결합도를 떨어뜨릴 수 있다.
- xyz.itwill01.old(패키지) ⇒ 결합도 높은 버전
- helloMessageObject(클래스) // MessagePrintObject(클래스) // MessagePrintApp(클래스)
- HiMessageObject(클래스)
- 클래스 하나가 바뀌니 그 클래스와 관계있는 다른 클래스도 모두 바꾸어줘야 한다.
결합도가 높아서 유지보수가 힘들어진다. - 결합도를 낮추기위해 인터페이스를 이용하거나 팩토리 클래스를 이용하는거다.
- xyz.itwill02.factory(패키지) ⇒ 결합도 낮은 버전
- helloMessageObject(클래스) // MessageObject(인터페이스) // MessageObjectFactory(팩토리 클래스) // MessagetPrintObjec(클래스) // MessagePrintApp(클래스)
- HiMessageObject(클래스)
- Factory 클래스에 의해 객체로 생성되어 제공될 클래스 - 인터페이스를 상속받아 작성
(팩토리 클래스 쓰려면 꼭 인터페이스를 상속받아야 한다.)
MessageObject (인터페이스) |
|
MessageObjectFactory (팩토리 클래스) |
반응형
댓글