Total: Today: Yesterday:
개발/JAVA | 2019. 6. 2. 19:00 | Posted by 자수씨

개요

spring-session 에 저장방식을 redis 로 지정하고 redis 라이브러리를 lettuce 로 지정하였다.

개발서버에서는 정상적으로 동작하였으나 운영서버에서는 같은 AWS EC2 인스턴스임에도 아래와 같은 오류가 발생하였다.

java.lang.ClassCastException: io.netty.channel.epoll.EpollEventLoopGroup cannot be cast to io.netty.channel.EventLoopGroup
    at io.lettuce.core.resource.DefaultEventLoopGroupProvider.getOrCreate(DefaultEventLoopGroupProvider.java:119) ~[lettuce-core-5.1.6.RELEASE.jar:na]

작업1

lettuce Native-Stransports 를 보면 native netty 의 성능이 더 좋으므로 netty-transport-native-epoll 을 디펜던시에 추가하라고 명시되어 있다.

디펜던시를 추가하고 웹 어플리케이션을 재시작하면 위와 같은 오류는 발생하지 않는다. 하지만 로컬 환경에서 native 디펜던시를 추가하는 것은 또다른 문제가 발생할 것으로 보여 다른 방법을 찾아야 했다.

작업2

lettuce Native-Stransports 를 자세히 살펴보니 native netty 를 사용하지 않는 옵션을 발견하였다.

catalina.sh 에 다음과 같이 시스템 프로퍼티를 추가한다.

# netty native settings
JAVA_OPTS="$JAVA_OPTS -Dio.lettuce.core.epoll=false"

재시작 시 native netty 를 사용하지 않고 정상동작 하는 것을 확인하였다.

INFO 15189 --- [enerContainer-1] io.lettuce.core.EpollProvider            : Starting without optional epoll library
INFO 15189 --- [enerContainer-1] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library

작업3

EPollProvider 를 보다보니 io.netty.channel.epoll.Epoll 클래스가 있는지를 체크하는데 저 클래스로 인해 native netty 가 활성화 된 것으로 추가한 기억이 없는 클래스의 위치를 찾기 위해 classloader.jsp 를 인터넷에서 구하여 위치를 확인해보았다.

예전에 tomcat session 을 redis 로 설정하기 위해 ${catalina_base}/lib 에 추가하였던 redis-session-manager-with-dependencies-2.2.2-SNAPSHOT.jar 이 파일이 문제였다. 이번 작업으로 인해 제거해도 무방했던 jar 파일이라 제거하고 테스트를 해보았더니 정상이였다.

결론

문제의 원인은 이전에 추가하였던 redis-session-manager 라이브러리와의 충돌이였다. 어쩐지 인터넷을 찾아봐도 비슷한 내용이 나오지 않더라니...

돌고 돌았지만 문제의 원인은 확인하고 해결할 수 있었다.

개발/JAVA | 2015. 4. 28. 08:38 | Posted by 알 수 없는 사용자


iBatis -> MyBatis


 

 


1       Ibatis에서 MyBatis로 변경된 이유

Ø  Apache project팀에서 google code팀으로 이동하면서 명칭이 변경됨.

 

2       차이점

2.1      Java 요구 버전

Ø    iBatis에서는 JDK 1.4 이상에서 사용 가능 MyBatis에서는 JDK 1.5 이상 사용 가능.

2.2      패키지 내부 구조가 변경되었음.

Ø    ibatis : com.ibatis.*

Ø    MyBatis : org.apache.ibatis.*

2.3      sqlMap.xml 내부 구조가 변경되었음.

Ø    parameterMap 사용 못함. -> parameterType으로 대체.

Ø    dtd가 변경 (“http://mybatis.org/dtd/mybatis-3-mapper.dtd”>

Ø    사용 용어의 변경

SqlMapConfig

Configration

sqlMap

Mapper

resultClass

resultType

 

2.4      MyBatis lib 별도 제공

Ø    Maven Dependency Information 예시

<dependency>

    <groupId>org.mybatis</groupId>

   <artifactId>mybatis</artifactId>

   <version>3.2.2</version>

</dependency>

 

<dependency>

   <groupId>org.mybatis</groupId>

   <artifactId>mybatis-spring</artifactId>

    <version>1.2.0</version>

</dependency>

 

2.5      Annotation 도입

Ø    sqlMapClient DI 설정 불필요

Ø    간편해짐

Ø    Bean id sqlSesstionFactory, sqlSesstionTemplate만 지정하면 됨.

2.6      rowHandler 대체

Ø    xml및 대량 데이터 처리를 위해 사용되었던 rowHandler가 삭제

Ø    rowHandler -> resulthandler로 변경됨

Ø    자바 annotation을 사용하여 xml을 사용하지 않고 자바로만 할 수 있게 됨.

Ø    자바 선언 보다 xml 선언이 우선순위를 가짐.

2.7      네임스페이스 방식 변경

Ø    ibatis : <sqlMap namespace=”User”>

Ø    MyBatis : <mapper namespace=”myBatis.mapper.UserMapper”>

Ø    네임스페이스 사용은 필수, userStatementNameSpace설정 제거

2.8      동적 SQL – XML 엘리먼트

Ø    If, choose(when, otherwise), trim (whre,set), foreach

2.9      동적 SQL – Provider annotation

Ø    @SelectProvider(type=CommentSqlProvider.class, method=”selectCommentByCondition”)

2.10    캐시 지원.

2.11    (스프링 연동모듈) mapper 자동 검색


 

3       변경되거나 추가된 속성들 (종합)

4       iBatis

MyBatis

비고

com.ibatis.*

org.apache.ibatis.*

패키지 구조 변경

SqlMapConfig

Configration

용어변경

sqlMap

mapper

용어변경

sqlMapClient

sqlSession

구문대체

rowHandler

resultHandler

구문대체

resultHandler

SqlSessionFactory

구문대체

parameterMap, parameterClass

parameterType

속성 통합

resultClass

resultType

용어변경

#var#

#{var}

구문대체

$var$

${var}

구문대체

<isEqual> , <isNull>

<if>

구문대체




일 작업하면서 정리하였던거 공유합니다.


 

개발/JAVA | 2015. 3. 3. 15:58 | Posted by 자수씨

출처: http://codereview.stackexchange.com/questions/59428/validating-utf-8-byte-array


charset 이 불확실한 상황에서 여러 시스템에서 xml 기반 데이터를 주고 받다보면 charset 으로 인해 문베가 발생하곤한다.


A라는 시스템에서는 xml 은 utf-8 기반인데, 안에 있는 내용(BASE64 로 인코딩한)은 euc-kr 방식이고, B라는 시스템에서는 xml 은 utf-8 기반이고, 안에 있는 내용도 utf-8 방식이다.


위의 상황이라면 A와 B를 둘 다 만족시킬 수 있는 시스템을 만들기 위해서는 byte array 가 utf-8 인지 euc-kr 인지 구분이 필요하다.

(utf-8로 디코딩해야 하는 상황이라면 아래의 검사 후 utf-8이 아니라면 euc-kr 로 다시 디코딩)


참고했던 페이지는 Java 7 기반으로 되어 있어서 Java 6 기반으로 바꾸어보았다.


in Java 6

###java

public class ValidateUtf8 {


    /**

     * Returns the number of UTF-8 characters, or -1 if the array does not

     * contain a valid UTF-8 string. Overlong encodings, null characters,

     * invalid Unicode values, and surrogates are accepted.

     *

     * @param bytes byte array to check length

     * @return length

     */

    public static int charLength(byte[] bytes) {

        int charCount = 0, expectedLen;


        for (int i = 0; i < bytes.length; i++) {

            charCount++;

            // Lead byte analysis

            if ((bytes[i] & Integer.parseInt("10000000", 2)) == Integer.parseInt("00000000", 2)) {

                continue;

            } else if ((bytes[i] & Integer.parseInt("11100000", 2)) == Integer.parseInt("11000000", 2)) {

                expectedLen = 2;

            } else if ((bytes[i] & Integer.parseInt("11110000", 2)) == Integer.parseInt("11100000", 2)) {

                expectedLen = 3;

            } else if ((bytes[i] & Integer.parseInt("11111000", 2)) == Integer.parseInt("11110000", 2)) {

                expectedLen = 4;

            } else if ((bytes[i] & Integer.parseInt("11111100", 2)) == Integer.parseInt("11111000", 2)) {

                expectedLen = 5;

            } else if ((bytes[i] & Integer.parseInt("11111110", 2)) == Integer.parseInt("11111100", 2)) {

                expectedLen = 6;

            } else {

                return -1;

            }


            // Count trailing bytes

            while (--expectedLen > 0) {

                if (++i >= bytes.length) {

                    return -1;

                }

                if ((bytes[i] & Integer.parseInt("11000000", 2)) != Integer.parseInt("10000000", 2)) {

                    return -1;

                }

            }

        }

        return charCount;

    }


    /**

     * Validate a UTF-8 byte array

     *

     * @param bytes byte array to validate

     * @return true if UTF-8

     */

    public static boolean validate(byte[] bytes) {

        return (charLength(bytes) != -1);

    }

}



in Java 7 이상

### java

public class ValidateUtf8 {


    /**

     * Returns the number of UTF-8 characters, or -1 if the array does not

     * contain a valid UTF-8 string. Overlong encodings, null characters,

     * invalid Unicode values, and surrogates are accepted.

     *

     * @param bytes byte array to check length

     * @return length

     */

    public static int charLength(byte[] bytes) {

        int charCount = 0, expectedLen;


        for (int i = 0; i < bytes.length; i++) {

            charCount++;

            // Lead byte analysis

            if ((bytes[i] & 0b10000000) == 0b00000000) {

                continue;

            } else if ((bytes[i] & 0b11100000) == 0b11000000) {

                expectedLen = 2;

            } else if ((bytes[i] & 0b11110000) == 0b11100000) {

                expectedLen = 3;

            } else if ((bytes[i] & 0b11111000) == 0b11110000) {

                expectedLen = 4;

            } else if ((bytes[i] & 0b11111100) == 0b11111000) {

                expectedLen = 5;

            } else if ((bytes[i] & 0b11111110) == 0b11111100) {

                expectedLen = 6;

            } else {

                return -1;

            }

            // Count trailing bytes

            while (--expectedLen > 0) {

                if (++i >= bytes.length) {

                    return -1;

                }

                if ((bytes[i] & 0b11000000) != 0b10000000) {

                    return -1;

                }

            }

        }

        return charCount;

    }


    /**

     * Validate a UTF-8 byte array

     *

     * @param bytes byte array to validate

     * @return true if UTF-8

     */

    public static boolean validate(byte[] bytes) {

        return (charLength(bytes) != -1);

    }

}


개발/JAVA | 2015. 2. 11. 18:03 | Posted by 알 수 없는 사용자

담당하고 있는 모듈의 프로젝트가 여러개일때 버전 관리 문제로 자수씨의 도움으로 메이븐방식으로 프로젝트 구조를 잡게 되었다.

프로젝트 안에 프로젝트들이 있다고 생각하면 쉽다.

관리도 프로젝트 하듯이 관리하면 된다.


구조 만들기

1. 메이븐 프로젝트를 생성한다.

 

또는   에서 Maven Project 검색

2. 딱히 설정할 것 없으면 next

* 꼭 위에 선택한대로 선택 안해도 된다


3. Group Id, Artifact Id 필수 입력 입니다. 입력하고 Finish


6. 프로젝트를 생성하면 아래와 같이 구조가 잡힌다.



위의 pom.xml을 열어 수정한다.  >>     -> 



7. 부모 부로젝트는 소스 부분이 필요 없으니 실제 프로젝트가 작업 공간으로 이동해서 네모 친 부분 삭제.

* 소스가 필요 없다면 굳이 .settings 폴더에 org.eclipse.jdt.core.prefs가 필요없다.


8. 삭제하고 난 뒤 이클립스에서 보여지는 프로젝트


9. 본격적으로 자식 프로젝트들을 추가한다. 

또는   에서 Maven Module 검색


10. 네모친 부분 입력하고 working set 경로 확인하고 next 후 finish

* 아래 네모는 자동으로 입력된다. finish


그럼 이제 프로젝트 안에 모듈이 포함되었다.

* 이클립에서 모듈이 추가되었을때 보여지는 화면

간단하게 설명하자면 

test-module (부모프로젝트) test-module-ui 라는 모듈을 포함시키면서 test-module-ui 프로젝트 가 만들어지면서 포함되는 형식.

따라서 test-module-ui 프로젝트와 test-module프로젝트의 test-module-ui 모듈은 같은거다.


9 - 10 단계를 거쳐 또 다른 모듈을 추가 시킨다면 아래와 같이 두개 생성 된다.



test. 프로젝트에서 수정하였 을 때 모듈에서 적용 될까?


test-1. App.java

 


test-2. 이름 바꿈.


test-1. 이름이 바뀜.


* 참고 *

부록 - 부모 폼 정보 / test-module.pom.xml


부록 - 자식 폼 정보 / test-module-ui.pom.xml

부록 - 자식 폼 정보 / test-module-server.pom.xml


버전 관리 방법

부모 폼에서 버전을 수정하면 자식 모듈의 버전 정보를 수정하면 끝이다.


<추가>

위 구조로 되어있는 프로젝트가 SVN으로 올라 왔을 경우 체크아웃 받을때 자동으로 프로젝트를 잡지 못한다.

이럴 경우 import > Maven > Existing Maven Projnect 를 선택하는 것을 참조한다.