개발을 하다가 여러 코드들을 보면 자주 보는 키워드가 있습니다.

바로 ' var ' 인데요.

 

JavaScript를 개발하면서 이제 더 이상  ' var '  를 사용하면 좋지 않습니다!

 

그 이유는,

첫 번째로 보통 java, c언어 등 변수를 선언하기도 전에 해당 변수를 출력하면 에러가 발생합니다.

하지만 var를 사용하면 

 

console.log(a);

a = 4;

var a;

 

이렇게 코드를 작성하면 에러가 발생하지 않습니다.

 

왜  var를 사용하면 에러가 나지 않을까요?

 

var에는 "var hoisting" 이라는 것이 있습니다.

 

 

 

Var hoisting

 

1. hoisting은 어느 위치에 변수를 선언하더라도 상관없이 제일 상단으로 var 변수를 끌어 올린다.

 

즉, 변수를 선언하기도 전에 console.log를 선언해도 var변수를 아무곳에 선언만 했다면
에러가 나지 않는다.

 

2. Block Scope가 없다.

프로젝트에 logback 적용에 이해 Transaction을 적용하도록 하겠습니다.

Transaction의 방식에는 두 가지 방법이 있습니다.

1. @Transaction을 이용해 적용한다.

2. root-context.xml(spring regacy project) 또는 dispatcher-servlet-xml(maven project)에 해당 서비스 Impl을 지정하여 전체 Transaction을 적용한다.

 

1번과 2번의 차이는 확연합니다.

 

1번의 방식을 진행하면 필요한 것만 할 수 있다.

2번의 방식을 진행하면 간편하게 묶어 줄 수 있다.(1번의 방식으로 많은 service 메서드들을 하나하나 적용하기 힘들다.)

 

저희는 2번의 방법을 사용할것입니다.

이제 프로젝트에 적용해보도록 하겠습니다.

 

		<!-- pom.xml -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.3.2.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.9.5</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.9.5</version>
		</dependency>

 

여기서 알아야 할 것이 있는데

@Transaction을 사용하려면 cglib 라이브러리를 dependency에 추가해야 합니다.

추가해야하는 이유는 차후에 작성하도록 하겠습니다.

 

<!-- dispatcher-servlet.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  <!-- 추가 -->
	xsi:schemaLocation="
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  <!-- 추가 -->
		 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd  <!-- 추가 -->
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- net.eduSample로 시작하는 패키지를 모두 등록 -->
	<!-- <context:component-scan base-package="net.eduSample" /> -->
	<context:component-scan base-package="net.eduSample.*" />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/jsp/</value> <!-- 접두어 -->
		</property>
		<property name="suffix">
			<value>.jsp</value> <!-- 접미어 -->
		</property>
	</bean>

	<!-- <mvc:resources mapping="/resources/**" location="/resources/" /> -->
	<mvc:resources mapping="/static/**" location="/static/" />
	<mvc:resources mapping="/favicon.ico" location="/WEB-INF/img/common/favicon.ico" />

	<mvc:annotation-driven />

	<bean id="AdminInterceptor" class="net.eduSample.interceptor.AdminInterceptor" />

	<!-- Interceptor 설정 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/admin/**" />
			<mvc:mapping path="/user/userAll" />
			<mvc:mapping path="/user/userIntegrated" />
			<mvc:mapping path="/user/userHistory" />
			<!-- <mvc:exclude-mapping path="/resources/**"/> -->
			<ref bean="AdminInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>
	
	
	<!-- transaction -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" /> <!-- 트랜잭션 대상 선정. 바뀔 일 없고 이후 복사해서 사용 -->
	</bean>

	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" rollback-for="Exception" />
		</tx:attributes>
	</tx:advice>

	<!-- package net.eduSample.sample.service.impl -->
	<aop:config>
		<aop:pointcut id="txPointcut"
			expression="execution(* net.eduSample.sample.service.impl.*ServiceImpl.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
	</aop:config>

	<tx:annotation-driven transaction-manager="transactionManager"
		proxy-target-class="true" />


</beans>

 

다음과 같이 적용 후 

serviceImpl 파일로 가서 insert와 update를 진행하는 메서드를 작성 후

insert나 update 중 하나를 mapper에 고의로 오타를 내서 확인해보면

에러가 나도 DB에 값이 들어가지 않고 모두 롤백되는것을 볼 수 있습니다.

 

victorydntmd.tistory.com/173

 

[Spring] 로그 남기기 ( Logback )

로그 ( Log ) 로그는 기록을 남기는 것을 의미합니다. 구체적으로는 프로그램 개발이나 운영 시 발생하는 문제점을 추적 하거나 운영 상태를 모니터링 하는 정보를 기록하는 것이죠. 또한 분석을

victorydntmd.tistory.com

해당 블로그를 참조하였습니다.

 

안녕하세요

저는 프로젝트에서 log를 찍을 때 log4j를 사용했었는데 성능 및 기능상의 이유로 logback으로 변경하고,

log를 C드라이브 아래 or 서버(본인은 ec2)에 파일로 저장하도록 하겠습니다.

 

log4j를 사용할 때는 commons.logging 라이브러리(JCL, Jakarta Commons Logging) 을 사용하는데요

스프링의 로그는 JCL에 의존하여 로그가 찍히게 되는 것 입니다.

 

pom.xml에 

spring-context 라이브러리를 추가하면 spring-context안에 commons-logging 라이브러리도 같이 존재합니다.

 

logback 라이브러리를 사용하려면 SLF4J가 필요합니다.(SLF4J : JCL과 Log4J를 이어주는 역할)


라이브러리들 안에 있는 commons-logging을 제외하도록 하겠습니다.

그리고 logback을 하기위한 dependency도 추가하도록 하겠습니다.

 

<!-- pom.xml -->

<properties>
		<jcloverslf4j.version>1.7.6</jcloverslf4j.version>
		<logback.version>1.1.1</logback.version>
</properties>

<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.3.24.RELEASE</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
</dependency>
        
<dependency>
			<groupId>org.springframework</groupId>  <!-- JCL 제외 -->
			<artifactId>spring-context</artifactId>
			<version>4.3.24.RELEASE</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
</dependency>


<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${jcloverslf4j.version}</version>
</dependency>

<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
</dependency>

 

exclusion태그로 JCL을 제외시키면 기존에 로그를 남기는 코드는 에러를 발생시키는데

jcl-over-slf4j 라이브러리가 중간의 매개체가 되어서

실제로는 logback-classic 라이브러리가 로그를 남기게 됩니다.

 

이제  src/main/resources 위치에 logback.xml을 생성하여 로그를 남길 수 있도록 작성하겠습니다.

 

<!-- src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
 [Layout]
 %m : 로그내용이 출력
 %p : trace > debug > info > warn > error 등의 priority 출력
 %r : 어플리케이션이 시작되어 로깅이벤트가 발생하는 시점까지의 경과시간을 밀리세컨드로 출력
 %c : 예) 카테고리가 a.b.c 처럼 되어있다면 %c{2}는 b.c가 출력됩니다.
 %n :  플랫폼 종속적인 개행문자가 출력된다. \r\n 또는 \n 일것이다
 %d : 로깅이벤트가 일어나 날짜 출력 ( 프로그램의 실행속도를 느리게 한다.)
     예) %d{HH:mm:ss} 또는 %d{dd MMMM yyyy HH:mm:ss}
 %C : 호출자의 클래스명 출력
    예) 클래스구조가 org.apache.xyz.SomeClass 처럼 되어있다면 %C{2}는 xyz.SomeClass 가 출력됩니다
 %M : 로깅이 발생한 method 이름을 나타냅니다.
 %F : 로깅이 발생한 프로그램 파일명을 나타냅니다.
 %l : 로깅이 발생한 caller의 정보를 나타냅니다 
 %L : 로깅이 발생한 caller의 라인수를 나타냅니다 
 %x : 로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력합니다. 
 %X : 로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력합니다. 
 %% : % 표시를 출력하기 위해 사용한다.  
 %t : 로그이벤트가 발생된 쓰레드의 이름을 출력합니다
-->

<configuration scan="true" scanPeriod="30 seconds">
    
    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- rollover daily -->
            <fileNamePattern>/edu-project/logs/jys/logback-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 100MB -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%-5level] - %msg%n</Pattern>
        </layout>
    </appender>
    
    <!-- Loggers -->
    <logger name="org.apache.catalina" level="ERROR">
    </logger>
    
    <logger name="org.apache.commons" level="ERROR">
    </logger>
    
    <logger name="org.springframework" level="DEBUG" >
    </logger>
    
    <logger name="java.sql" level="DEBUG">
    </logger>
    
    <logger name="org.mybatis.spring" level="DEBUG">
    </logger>
    
    
    <root level="DEBUG">
       <appender-ref ref="ROLLING"/>
       <appender-ref ref="STDOUT" />
    </root>
</configuration>

 

해당 코드에 <fileNamePattern>을 보시면

 

<fileNamePattern>/edu-project/logs/jys/logback-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> 

 

다음과 같이 '/'로 경로를 표현하는데 이는 지금 저는 ec2서버로 파일을 저장할 것이기 때문에 '/'로 표현했으며

로컬 C드라이브 밑에 저장하고 싶다면 

 

<FileNamePattern>C:\test\test.%i.log.zip</FileNamePattern>

 

'\'로 작성해야 합니다.

 

이는 리눅스와 윈도우는 각각 '/'와 '\'를 사용하기 때문입니다.

 

 

그리고 특정 라이브러리에 commons-logging 라이브러리가 포함되어 있을 수 있기 때문에

 

 

라이브러리를 확인하여 만약 commons-logging 라이브러리가 있다면

<exclusion>로 commons-logging 라이브러리를 제외시켜야 정상 작동 된다는 것을 

알고계시면 좋을 것 같습니다.

+ Recent posts