gradle에서 특정 라이브러리는 사용하고 싶지 않다면.


configuration-> compile.exclude를 사용한다.




주의할 점은 group, module이 분류되어 있다는 점이다.



configurations {
compile.exclude group: "org.slf4j", module : "slf4j-log4j12"
compile.exclude group: "javax.servlet", module : "servlet-api"
}


Posted by 김용환 '김용환'



Kafka에 zookeeper를 사용할 때. zookeeper 기본 설정 사용하다가 주키퍼에서 메모리 부족하고 난리도 아니다.


메모리 설정과 jmx 설정을 해주는 것이 좋다.




conf/java.env파일을 추가해 메모리 설정도 gc 로그 파일을 생성한다. 아래는 대략 기본 설정으로 보는게 좋다.


export JVMFLAGS="-Xmx3g -Xms3g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:CompileThreshold=200 -verbosegc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/lib/zookeeper/gc.log -XX:+UseGCLogFileRotation -XX:GCLogFileSize=10m -XX:NumberOfGCLogFiles=10"



zkServer.sh에 다음을 추가해 jmx 모니터링을 진행한다.


-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8989 -Djava.rmi.server.hostname=my.remoteconsole.org





Posted by 김용환 '김용환'




요즘에 https://github.com/square/okhttp은 점차 안드로이드 진영에서 인정받으면서 서버단에서 많이 쓰기 시작하고 있다. 

okhttp에 pooling이 내부적으로 되어 있어서, 편하게 사용가능하다.



OKHttpClient를 생성할 때 OKHttpClient.Builder를 호출하는데, 기본 생성자인 ConnectionPool을 생성하면서 5개 connection을 자동으로 생성한다.





https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/OkHttpClient.java



https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/OkHttpClient.java#L487



https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/ConnectionPool.java#L85


 

public ConnectionPool() {

this(5, 5, TimeUnit.MINUTES);

}



Posted by 김용환 '김용환'


자바 개발할 때 json 파싱은 사실 상 헬이다..


Apache Nifi에서 사용하고 있는 JsonPath(https://github.com/json-path/JsonPath)는 성능도 괜찮고, 캐시 기능이 있어서 여러 번 파싱하지 않아도 되고... 조건 검색, REGEX 검색도 가능하고 아주 쓸만하다.



예제는 홈피에 있다. (scala의 json4s보다 훨 나은 느낌이다..)

Path Examples

Given the json

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    },
    "expensive": 10
}
JsonPath (click link to try)Result
$.store.book[*].authorThe authors of all books
$..authorAll authors
$.store.*All things, both books and bicycles
$.store..priceThe price of everything
$..book[2]The third book
$..book[-2]The second to last book
$..book[0,1]The first two books
$..book[:2]All books from index 0 (inclusive) until index 2 (exclusive)
$..book[1:2]All books from index 1 (inclusive) until index 2 (exclusive)
$..book[-2:]Last two books
$..book[2:]Book number two from tail
$..book[?(@.isbn)]All books with an ISBN number
$.store.book[?(@.price < 10)]All books in store cheaper than 10
$..book[?(@.price <= $['expensive'])]All books in store that are not "expensive"
$..book[?(@.author =~ /.*REES/i)]All books matching regex (ignore case)
$..*Give me every thing
$..book.length()The number of books


Posted by 김용환 '김용환'



apache commons에 CircularFifoBuffer 클래스가 있다. 



첫번째 예시 코드이다.



object Test extends App {

import org.apache.commons.collections.buffer.CircularFifoBuffer

val tasks = new CircularFifoBuffer(10)
tasks.add(1)
tasks.add(2)
tasks.add(5)
tasks.add(6)
println("max size : " + tasks.maxSize)
println("size: " + tasks.size)
println("--get")
println(tasks.get())
println(tasks.get())
println(tasks.get())
println(tasks.get())

println("--remove")
println(tasks.remove)
println(tasks.remove)
println(tasks.remove)
println(tasks.remove)

println("-- error")
println(tasks.remove)
}


가지고 있는 buffer보다 더 많이 remove하면 exception이 발생한다. 

get을 호출하면 계속 첫번째 엘리먼트를 리턴한다. 현재 값 확인할 때 좋을 듯 하다. 


max size : 10

size: 4

--get

1

1

1

1

--remove

1

2

5

6


at org.apache.commons.collections.buffer.BoundedFifoBuffer.remove(BoundedFifoBuffer.java:275)





두 번째 예시 코드이다. 


object Test extends App {

import org.apache.commons.collections.buffer.CircularFifoBuffer

val tasks = new CircularFifoBuffer(10)
tasks.add(1)
tasks.add(2)
tasks.add(3)
tasks.add(4)
tasks.add(5)
tasks.add(6)
tasks.add(7)
tasks.add(8)
tasks.add(9)
tasks.add(10)
tasks.add(11)
tasks.add(12)
println("max size : " + tasks.maxSize)
println("size: " + tasks.size)

for(i <- tasks.toArray) {
println(tasks.remove)
}
}


데이터를 계속 추가하면 처음에 들어온 데이터는 삭제된다. overflow가 발생되지 않는다. 



max size : 10

size: 10

3

4

5

6

7

8

9

10

11

12


Posted by 김용환 '김용환'


젠킨스에서 반복적인 job은 job dsl 플러그인을 쓰면 편하다~

multi-job 대신 쓸만할 수도. 


https://wiki.jenkins.io/display/JENKINS/Job+DSL+Plugin



Configuration As Code: The Job DSL Plugin de Daniel Spilker




Posted by 김용환 '김용환'




jenkins pipeline 플러그인은 사용하면 각 단계로 로그를 상세히 볼 수 있다!!!





어디 단계에서 문제가 발생하는지 보니까 완전 좋다!!



한국 분의 설치 내용

https://shortstories.gitbooks.io/studybook/content/jenkins_pipeline_c0bd_c9c8_ae30.html



결과 내용


참조 : https://www.cloudbees.com/blog/top-10-best-practices-jenkins-pipeline-plugin


 



Posted by 김용환 '김용환'

java8 stream 사용시 주의할 점을 작성한 좋은 블로그 내용이 있어서 링크를 건다.



https://blog.jooq.org/2014/06/13/java-8-friday-10-subtle-mistakes-when-using-the-streams-api/



이 내용을 이용진 블로거님이 번역한 블로그이다.


http://leeyongjin.tistory.com/entry/Java8-%EC%9E%90%EB%B0%948-Stream-API-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD


Posted by 김용환 '김용환'




java9을 설치하니 Spring Tool Suite가 동작이 되지 않는다. 


!ENTRY org.eclipse.e4.ui.workbench 4 0 2017-10-20 19:29:56.365

!MESSAGE FrameworkEvent ERROR

!STACK 0

java.lang.NoClassDefFoundError: javax/annotation/PreDestroy

        at org.eclipse.e4.core.internal.di.InjectorImpl.disposed(InjectorImpl.java:426)

        at org.eclipse.e4.core.internal.di.Requestor.disposed(Requestor.java:154)

        at org.eclipse.e4.core.internal.contexts.ContextObjectSupplier$ContextInjectionListener.update(ContextObjectSupplier.java:78)

        at org.eclipse.e4.core.internal.contexts.TrackableComputationExt.update(TrackableComputationExt.java:111)

        at org.eclipse.e4.core.internal.contexts.TrackableComputationExt.handleInvalid(TrackableComputationExt.java:74)

        at org.eclipse.e4.core.internal.contexts.EclipseContext.dispose(EclipseContext.java:176)

        at org.eclipse.e4.core.internal.contexts.osgi.EclipseContextOSGi.dispose(EclipseContextOSGi.java:106)

        at org.eclipse.e4.core.internal.contexts.osgi.EclipseContextOSGi.bundleChanged(EclipseContextOSGi.java:139)

        at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:903)

        at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)

        at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)

        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:213)

        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:120)

        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:112)

        at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:156)

        at org.eclipse.osgi.container.Module.publishEvent(Module.java:476)

        at org.eclipse.osgi.container.Module.doStop(Module.java:634)

        at org.eclipse.osgi.container.Module.stop(Module.java:498)

        at org.eclipse.osgi.container.SystemModule.stop(SystemModule.java:191)

        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule$1.run(EquinoxBundle.java:165)

        at java.base/java.lang.Thread.run(Thread.java:844)

Caused by: java.lang.ClassNotFoundException: javax.annotation.PreDestroy cannot be found by org.eclipse.e4.core.di_1.6.0.v20160319-0612

        at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:398)

        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:361)

        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:353)

        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)

        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)

        ... 21 more





STS.ini에서 -vmargs 라인을 찾고 다음을 추가한다.


-vmargs

--add-modules=java.se.ee



참고로 STS.ini 파일은 STS.app/Contents/Eclipse에 위치한다. 



Posted by 김용환 '김용환'




maven에서 매개변수를 전달하는 방법은 exec.args를 사용한다.


특별히 스페이스가 포함된 문자열을 하나의 토큰으로 전달하려면 sing quote를 사용한다. 



예제


$ maven exec:java -Dexec.mainClass=com.google.photo.Main  -Dexec.args="local 'a   a' "




만약 classpath나 jvm 옵션을 추가하고 싶다면 아래와 같이 사용한다.



예제



$ mvn exec:exec -Dmaven.run.skip=true -Dexec.executable="java"  -Dexec.args="-classpath /usr/local/apache-storm-1.0.1/lib/*:/home/google/lib/photo.jar com.google.photo.Main local"



Posted by 김용환 '김용환'