spring boot

springBoot gradle 2016. 12. 18. 01:07

설치는 SDKMAN 이나 Brew등으로 가능.

$spring --version 으로 버전확인 가능.

$spring shell  :  sh도 제공


하지만, 대부분 IDEA를 이용하므로,

IntelliJ를 이용할 경우, gradle프로젝트를 만들고, springboot는 dependency로 삽입하면 된다. REF




<어노테이션>

@SpringBootApplication : component-scan 과 자동config제공.

  - @Conditional 도 가능( jdbcTemplate과 같이 dataSource존재여부에 따라...조건부 Bean제공 가능)

한데 자동 config은 이런식으로 Tomcat, ORM, web매핑(/static) 등으로 classpath등을 보고 자동판단한다.


*물론 이러한 자동config도 override를 통해  수정할수 있다.(@Configuration)


<빌드 & run - gradle 사용시>

 $ gradle bootRun : 빌드와 run동시 수행.

    = $gradle build + $java -jar build/libs/..-0.0.1-SNAPSHOT.jar(or war)


maven :  $spring-boot:run

               

             ($ mvn package ) : just package



 <설정>

application.properties는 첨엔 비어있으므로 필요한걸 추가하면 됨.

dependency가 2개가 있는데(gradle.plugin 등)

  - 위에껀 spring boot plugin dependency이고

  - 밑에껀 starter dependency 이다.   (참고로 maven은  순서가 바뀌어있지만.. plugin tag보면 알수 있음)


  - dependency 일부를 제거하고 싶을 땐,  exclude group등으로 가능.


 


 <TEST용 어노테이션>

@WithMockUser

@WithUserDetails


@WebIntegrationTest     


@Value (${local.server.port}) 등도 spring에서부터 사용가능.


물론 웹은 Sellenium과 연동테스트 된다.




<groovy> - C L I 와 궁합이 잘 맞음

Grabs.groovy 파일에 아래 3줄만 넣으면 spring-boot가 자동으로  못한 것들도, startup 시에 dependency를 자동으로 넣으면서 구동 가능. 

  @Grab("h2")

  @Grab("spring-boot-starter-thymeleaf")

  class Grabs {}  


==> 그 후에  $ spring run .  


 

Groovy로 test unit작성 시에는.. 

 $ spring test tests/myTest.groovy   로 하나 실행 혹은

 $ spring test tests  로 폴더통째로 실행 가능.



<패키징>

 $ spring jar MyProject.jar 하면 jar로 패키징 됨.. 


   war는 ?

   -gradle 의 경우 

      war {

baseName = 'readinglist'

version = '0.0.1-SNAPSHOT'

}

  - maven 의 경우

    <packaging> war </packaging>  

  

 만 추가하면 된다.



<Actuator>

CLI 환경에선 @Grab('spring-boot-starter-actuator') 추가하는 방법이 간단함.


그리고 Actuator중에선 아래 3가지가 특히 유용하다. . 

https://localhost:8080/beans  - 모든 bean과 dependency.  

https://localhost:8080/dump  - 모든thread 현황 

https://localhost:8080/trace   


그 외 enable을 시킨후에

curl -X POST http://localhost:8080/shutdown 명령어로 CLI상에서 shut-down도 가능하다. 



SSH 로도 actuator접속이 가능한데

@Grab("spring-boot-starter-remote-shell")  이런형태로나 maven/gradle에 dependency추가 후

$ ssh user@localhost -p 2000 하면 된다.






Posted by yongary
,

six2six FixtureFactory

java core 2016. 12. 12. 17:47

Unit 테스트시에 가짜 object를 만든다.

Template을 이용해서, class를 기본으로 object 데이타를 만든다.  REF




 Template을 이용하거나

  

     ClientTemplateLoader implements TemplateLoader{


@Override

public void load(){


}


Fixture.of(My.class).addTemplate("valid", new Rule(){{

}});

     }




 Fixture class안에서 ObjectFactory를 이용하게 되고.


     class Fixture {

         

        @Override

         ObjectFactory from(class<?> class){

    return new ObjectFactory(of(clazz)); 

}




Test시에는 아래와 같은 방법으로..  object를 만들어서 사용할 수 있게 된다.


  Fixture.from(My.class).gimme("new")    



- (물론)위처럼 소스에서 하나씩 생성할 수 있지만...


- Regex를 이용한 Rule을 이용해서도 만들 수도 있다. 

- Fixture 를 YAML로 저장해 놓고 일괄 생성할 수도 있다.



Posted by yongary
,

google Guava

java core 2016. 12. 8. 23:53

guava-api


Guava는 열대과일로서 분홍색 빛을 띤 주스로 즐기기기도 하는데,

구글에서는 guava library를 통해, java 에 없는 편리한 기능들을 진작부터 만들어왔고,

일부가 java7, java8등에 반영되기도 하였다.


거론되는 장점들은 다음과 같다. (추후 test후 재정리 예정)


1. MultiMap

 - 기존 Map이 <key,value>인데 반해,  MultiMap은 <key,v1,v2,v3,v4...>라고 볼 수 있다. 

   여러모로 편리하다. 속도도 구글이 만들었으니 빠를것 같긴 한데...   


2. ImmutableMap  : 

  - ImmutableMap.of( "A", ImmutableMap.of("A-1","A-2") )  ; 

  이런식으로 사용해서, data가 바뀌지 않는 Map 이 있어 test시에 유용하다.

    

  => ImmutableList.of("A","B"); 도 유용하다. (이거도 guava)


3. Ordering이 아주 편리하다고 한다. 



4. Maps.uniqueIndex  - 중복없는 Index 제공해주므로 편리.

    Maps.newHashMap() - nested Map 을 한번에 생성해서 편리.  REF (이전글이라 test필요) 



5. CharMatcher 가 아주편리하다고 한다.  regex를 대체할 수 있나 본데....



스트림에서 유용

 .stream().collect(GuavaCollectors.toImmutableMap

Posted by yongary
,

jackson (ObectMapper)

java core 2016. 12. 7. 17:49

Java 용 json parser로 가장 많이 사용되는 것이 jackson이 아닐까 싶다. : REF

 

jackson2 가 spring 4에 포함되면서,  RestController같은 경우 Object만 return 하면 자동으로

    MappingJackson2HttpMessageConverter에 의해 json으로 변환된다. : REF 

    ( 단, 모든 member변수에 gettersetter가 있어야 한다 - 이게 귀찮으니.. Lombok이 쓸만하다)

 

 

(복잡한 List<Object> 사용시에는 는)

     itemList = objectMapper.readValue(StringData, new TypeReference<List<MenuItemVo>>() {});

 

 

 

간단한 사용법은 다음과 같다. 

 

 

클래서 선언이 다음과 같을 때,

class MyObject{

String name;

int age;

}

 

import com.fasterxml.jackson.databind.ObjectMapper;

<json ->  java Object 방법>

 

   ObjectMapper mapper = new ObjectMapper();

   MyObject my = mapper.readValue ( file or URL or String , myObject.class);

  

   

 

<java Object -> json 방법>

  

  MyObject my = new MyObject("name", 12 );

  String jsonStr = mapper.writeValueAsString ( myObject )

  

  결과는 

  {"name":"name", "age":12 } 로 되는데

 

  좀 이쁘게 개행도 포함하고 싶으면

  String jsonStr = mapper.writeWithDefaultPrettyPrinter().writeValueAsString ( myObject );   으로 한다.

 

 

<변수명이 좀 다를때>

objectMapper.setPropertyNamingStrategy(     PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

20년에 위에껀 deprecated되고. 아래와 같이 하면 snake_case 를 camelCase로 변환됨. 단 snake_case는 소문자임.

    @Data
    public static class Camel {
        String userName;
    }

    @Test
//    @Tag("excludeBuild") //테스트시 comment 필요.
    public void mapperTest() throws Exception{
        
        ObjectMapper mapper1 = new ObjectMapper().setPropertyNamingStrategy(
                PropertyNamingStrategy.SNAKE_CASE);
        Camel camel1 = mapper1.readValue ("{\"user_name\":\"Kim\"}", Camel.class );

        log.info("Camel1:" + camel1);

개선: 아래로 하면 대문자도 되는 듯

+        mapperDome.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());

 

 

spring등에선 @JsonProperty로 변환용 변수명을 설정할 수 있지만,여러개일 경우 PropertyNameStrategy 설정이 매우 유용하다.

<null은 제외>

@JsonInclude(JsonInclude.Include.NON_NULL) 

<LocalDateTime 변환>

@JsonSerialize(using = LocalDateTimeJsonSerializer.class) : Custom Serializer 이용. 

public class LocalDateTimeJsonSerializer extends JsonSerializer<LocalDateTime> {
    private static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS =
            DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");

    @Override
    public void serialize(LocalDateTime localDateTime,
                          JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(localDateTime.format(YYYY_MM_DD_HH_MM_SS));
    }
}

 

<Object Copy>

import org.apache.phoenix.shaded.org.apache.commons.beanutils.BeanUtils;

 

try {

 //멤버type과 이름이 딱맞는 애들만 쭉 copy해준다.

BeanUtils.copyProperties(destObj, srcObj);  

} catch (Exception e) {

e.printStackTrace();

Posted by yongary
,

Service-as-a-VM & Docker

Spring 2016. 12. 3. 03:34

서비스를 개발하다 보면, 여러개의 서브-서비스로 나누어지게 되고 개발도 따로 하게되는 문제가 있지만,

배포에서 큰 문제가 된다. java version이 다르다던가 하는 사소한 문제부터 복잡한 수많은 문제가 생기게 되면서

배보다 배꼽이 큰, 즉 개발보다 deploy가 더 어려워지는 경우도 발생이 되기 때문에,


이런문제를 해결하는 개념으로 Service-as-a-VM 이 등장하였다.

(넷플릭스에서는  AMI 패키지 방식으로 아마존EC2에 배포를 한다) AMI=아마존 머신 이미지.



 그러나, 

VM자체도 부하가 크고 배포도 상당히 어렵기 때문에,  

간단한 파일로 배포를 하고, 프로세스 형태로 동작하는 가벼운  Docker 가 훨씬 더 유리하게 되면서

spring-boot 에 Docker를 결합한 방법이 많이 사용되고 있다.  REF(source 포함)




<Docker>한글REF REF

 


Docker image는 read-only 파일시스템이다. 

   layer  구조라서 배포시에 없는 layer만 배포하면 되고, 이미지 생성도 필요한 것만 되므로 매우 빠르다


Docker container 는 1개 또는 몇개의 sandboxed process로 이루어진  running image이다.  즉 프로세스라고 보면 된다.

  container 단위로  포트 등이 격리가 된다.  



Posted by yongary
,

Orika - the mapper

java core 2016. 12. 2. 15:54

http://orika-mapper.github.io/orika-docs/



1. mapperFactory.classMap(Aclass, Bclass)

         .byDefault()  - 이름이 같은애들 자동 매핑

         .register()  - MapperFactory()에 등록.


        - 그 외 exclude()나 1Direction으로 map하는 방법도 존재.

        - 한쪽이 array라도 매핑가능. (index or first, last 이용) 

        - 한쪽이 classB의 List<A> 라도 가능  Bfield{ fieldOfA }

        - 한쪽이 Map<blabla,blabla2>라도 가능.  field{key}, field{value}

        - null 매핑 on/off도 가능.

        

- in line property:   user:{getName('user')|setBlaBla .. }  지원.

- 프로그래매틱하게 할 수 있도록, Property.Builder 지원.

- 상당히 복잡한 경우를 위해  (Introspector)PropertyResolver  존재.



2. mapperFactory.getMapperFacade()

    B = bMapper.map (A)


3. BoundMapperFacade< A, B>  bMapper = mapperFactory.getMapperFacade ( A,B)  :  성능이 좋음. 

   B = bMapper.map (A)






Posted by yongary
,

Lombok

java core 2016. 12. 2. 15:53

https://projectlombok.org/


@Data  만 추가하면  Creator/Getter/Setter/toString/hashCode 메쏘드들이 다 있는 것으로 간주됨. (핵심)


그 외

@Getter, @Setter, @Cleanup (Finally로 제거해 주는 효과)




<Constructor 3가지 옵션 > REF


@AllArgsConstructor

@RequiredArgsConstructor - parameter있는 생성자 만들어 주는데, 해당 필드에 @NonNull 추가 필요.

@NoArgsConstructor




상속시에는 부모클래스의 Field들도, equals & hashCode()함수에 포함하기 위해서 아래가 필요.

  => 단, 부모클래스도 자식클래스도 @Data를 사용해야 한다. 

@EqualsAndHashCode(callSuper=true)


Posted by yongary
,

Macbook 처음사용시

Mac 2016. 12. 1. 21:31

<스크롤>

터치패드와 매직마우스의 스크롤을 "자연스럽게"를 끄면 window와 동일하게 동작한다.

스크롤은 손가락 2개로 할 수 있다.


<우측클릭>

터치패드에서 손가락 두개로 누르면 된다.. 마우스는 오른쪽 귀퉁이 누르게 설정가능.


<런치패드 : f4 >

 손가락 4개를 펼치면 실행. 끌때는 반대로.


<독 : Dock> 세로선을 잡아서 끌면 크기를 줄일 수 있다



<미션컨트롤 : f3> 손가락 3개를 쓸어올린다. 끌때는 반대로


<터미널>   spotligit( 옵션+스페이스) 에서 terminal입력. 

                 


<단축키>

  • +Q: 창 닫기(quit)
  • +,: (현재 프로그램에 대한) 설정
  •  Ctrl+Space: 한영전환
  • + Shift+4: 영역 스크린샷
  • + Shift+4Space: 창 스크린샷
  • command++: 화면 확대
  • command+-: 화면 축소
  • Ctrl+Option+Space: 검색 창 열기
  • command+Space: Spotlight 검색창


<Library 폴더가 안보일때>

Finder->Go menu->Home   select  --->    View menu -> Show View Option 에서 Library 선택. 


Posted by yongary
,

[java8 in action  일부 참고]

 

한마디로, Collection은 data라고 한다면 Stream은 computation이다.

 

 

<특징 2가지>

1. PipeLining

  Stream 은 unix명령어인 pipeline( "|" ) 과 같이 순차적으로 data를 처리한다. 

  (단, 실제로 unix에선 pipeline을 순차적으로 처리하지 않고, 몇줄이라도 조금씩 output이 있으면 동시처리를 한다)

 

2. Internal iteration 

  - 코드상 눈에 보이지는 않지만, 내부적으로 iteration이 일어난다.

  - 단 한번 traverse가 가능하다.  이게 끝나면 다시 new stream을 가져와야 한다.

 

 

<operation 종류> - Builder패턴과 유사하게 chain을 통해 중간단계를 여러개 거쳐 최종물 생성.

 

1. Intermediate Operation : Terminal Operation을 만나야만 동작을 한다. 

 - map, filter 등과 같이 중간에 데이타를 가공한다.

 - sorted, distinct  

 - limit, skip

 - 한꺼번에 처리가 되는만큼, 내부 동작 순서는 최적화해서 바뀐다. 

  (예: limit먼저 실행하고 다른 것 들 실행. map과 filter를 merge해서 실행)

  

 

2. Terminal Operation : 반드시 이걸로 끝나야 한다. 그래야만 intermediate Operation도 동작을 한다.

 - collect   (주로 List, Map, an Integer 리턴)

   

   ㅁ Map으로 변경

someList.stream() .collect(Collectors.toMap(AClassName::getMyCode, AClassName::getName))

   ㅁ GroupingBy

someList.stream().

.collect(Collectors.groupingBy(  AClassName::getName  ) )

 

=> Map<String, List<Person>> 형태로 리턴됨.

 

   

   ㅁ guava와 함께 쓰면:   .collect(GuavaCollectors.toImmutableList());

jp.skypencil.guava:helper:1.0.1
<dependency>
  <groupId>jp.skypencil.guava</groupId>
  <artifactId>helper</artifactId>
  <version>1.0.1</version>
</dependency>

 - forEach  (void 리턴)

 - count   ( long 숫자 return)

 

 

 

ofNullable함께 사용: REF

map으로 예제: REF

Function protoype 이용예제: REF

 

 

 

<철학>

java8에서는 stream을 이용해 multicore 개발의 복잡함과,  multihread로 인한 오류확률을 줄이고자 한다. 

          

 -> stream은 multicore에서도 parallel한 환경에서 transparent하게 작업이 가능하다. 

 일반적으로, .stream()에서 .parallelStream()으로만 바꾸면, 별도의 multithread코드 없이 parallel작업이 된다.

 

 

 

 

<forEach 예제>

 

  "hey duke".chars().forEach (c -> System.out.println((char)c));    My-Ref

  someStream.forEach (  (oneItem) -> {

oneItem.weight -= 1; 

oneItem.height += 10;

  }

 

단, 단순한  forEach는 Collector 에도 있으므로,  list.forEach( item -> blabla ); 가 가능함.

 

Posted by yongary
,

Armeria

network개발 2016. 11. 15. 14:58

<주로 사용하는 기능들>

HttpResponse.aggregate() : CompletableFuture로 전환.

예) httpClient.get(uri.getPath()).aggregate()


Decorator: req나 response를 살짝바꾸는 역할. SoC(Seperation of Concern)가 가능.

- req,res가 같을 때는 SimpleDecoratorService를 상속 - req나 res의 type의 바뀔때는 DecoratorService를 상속 - 간단한 decorate()용 lambda도 있음.

<유용한 class - armeria thrift용 개발시에도 사용가능>

com.linecorp.armeria.common.metric.MetricLabel
      - Collector같은 애들에게, 이름을 붙여서, lambda에서 사용시 지정할 수 있다.


common.util.Functions.voidFunction (Consumer or BiConsumer)   : Consumer를 Function으로 변환. 

                                    .compose (Func12, Func23) -> Func(1,3)으로 변환.   그 외에도 각종 compose들 존재. 


common.HttpHeaders;

common.RequestContext;

server.logging.LoggingService;


<기존 netty꺼긴 하지만..유용class>

io.netty.util.AsciiString;


<Connector>

armeria's TomcatService always create a Request/Response instance.
<-> Tomcat's Http11Processor create them only once and this processor instance will be recycled.




REF-github


- 기존의 netty와는 달리 Http2.0을 지원한다.   HTTP2.0-REF
    (기존의 HTTP1 서비스와 호환성도 유지)

- JNI-based socket I/O 

BoringSSL-based TLS connections

- (Apache) Thrift  호환
   THttpClient와 호환. (Thrift-Over-Http)   

    참고:  Thrift - Binary communication을 위한 IDL로서 RPC사용을 위해 facebook에서 개발.

- Java EE Web Application이랑 호환.  (same TCP/IP port)



Posted by yongary
,