java Proxy 기능으로 AOP

proxy 기능으로 AOP를 만들어 보자!

java.lang.reflect 패키지에 InvocationHandler 인터페이스가 존재한다. 이 인터페이스를 이용해 AOP를 구현할 수 있다.
간단히 어떤수의 두배하는 메소드를 만들어보자

class TwiceImpl implements Twice {

    @Override
    public int twice(int x) {
        return x * 2;
    }
}

interface Twice {
    int twice(int x);
}

이 코드를 사용하려면 이렇게 하면 된다. 위의 클래스의 인터페이스를 만든이유는 인터페이스가 있어야 java의 Proxy AOP를 만들수있다.

Twice twice = new TwiceImpl();
System.out.println(twice.twice(5));

이제 InvocationHandler 인터페이스를 이용하여 AOP를 구현해보자

class JavaProxyHandler implements InvocationHandler {
    private Object target;

    public JavaProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("메소드 호출 전");
        int result = (int) method.invoke(target, args);
        System.out.println("메소드 호출 후");
        return result;
    }
}

이제 Proxy가 구현되었다.

그럼 Proxy 객체로 다시 호출해보자!

Twice twice = new TwiceImpl();
Class<? extends Twice> twiceGetClass = twice.getClass();
Twice twiceProxy = (Twice) Proxy.newProxyInstance(
        twiceGetClass.getClassLoader(),
        twiceGetClass.getInterfaces(),
        new JavaProxyHandler(twice));
System.out.println(twiceProxy.twice(5));

그럼 결과는 다음과 같을 것이다.

메소드 호출 전
메소드 호출 후
10

참고 : AspectJ로 구현한 AOP

rest api 개념 및 설계

REST

  • REST는 웹의 창시자(HTTP) 중의 한 사람인 Roy Fielding의 2000년 논문에 의해서 소개되었다. 현재의 아키텍쳐가 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다고 판단했기 때문에, 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍쳐를 소개했는데 그것이 바로 Representational State transfer (REST)이다.

REST 의 기본

  • rest는 요소로는 크게 리소스, 메서드, 메세지 3가지 요소로 구성된다. 예를 들어 이름이 Wonwoo인 사용자를 생성한다. 라는 호출이 있을 때 사용자는 생성 되는 리소스, 생성한다라는 행위는 메서드 그리고 이름이 Wonwoo인 사용자는 메세지가 된다. 이를 표현해보면
HTTP POST, http://localhost/users/
{
   "users" :{
       "name" : "Wonwoo" 
   }
}

와 같이 표현되며 생성한다는 의미를 갖는 메서드는 POST, 생성하고자 하는 대상이 되는 사용자라는 리소스는 http://localhost/users/라는 형태의 URL로 표현되며, 생성하고자 하는 사용자의 내용은 JSON 문서를 이용한다.

HTTP 메서드

메서드 의미
POST Create
GET Select
PUT Update
DELETE Delete
PATCH Update
  • 각각의 Post, Get, Put, Delete는 각각의 CRUD 메서드와 대응 된다.
  • Patch 라는 메서드는 Put과 동일한 의미이지만 Put은 해당자원을 전체 Update하라는 의미를 지닌 대신 Patch는 일부만 변경하겠다는 의미를 갖고 있다. 최근에는 Put보다 더 의미적으로 적합하다고 평가받고 있다.

REST의 리소스

  • Rest는 리소스 지향 아키텍쳐 스타일이라는 정의 답게 ㅗ든 것을 리소스 즉 명사로 표현을 하며, 각 세부 리소스에는 id를 붙인다. 즉 사용자라는 리소스 타입을 http://localhost/users 라고 정의했다면 Wonwoo라는 id를 갖는 리소스는 http://localhost/users/Wonwoo 라는 형태로 정의한다.
  • 예제로 통해 알아보자
    1. 사용자 생성

    • 다음은 http://localhost/users 라는 리소스로 이름은 wonwoo, 주소는 seongnam 이라는 내용을 이용해서 생성하는 표현이다.
HTTP Post, http://localhost/users
{
  "name" : "wonwoo",
  "address" : "seongnam"
}

2. 사용자 조회
– 다음은 생성된 리소스 중에서 http://localhost/users 라는 사용자 리소스중에, id가 wonwoo인 사용자 정보를 조회해오는 표현이다.

HTTP Get, http://localhost/users

3. 사용자 업데이트
– 다음은 생성된 리소스 중에서 http://localhost/users 라는 사용자 리소스중에 id가 wonwoo인 사용자정보에 대해 주소를 seoul으로 수정하는 표현이다.

HTTP PUT, http://localhost/users/wonwoo
{
  "address":"seoul"
}

4. 사용자 삭제
– 다음은 생성된 리소스 중에서 http://localhost/users 라는 사용자 리소스중에 id가 wonwoo인 사용자 정보를 삭제 하는 표현이다.

HTTP DELETE, http://localhost/users/wonwoo
  • 간단하게 CURD 표현이 끝났다.

REST의 특성

  1. 유니폼 인터페이스(Uniform Interface)
    • REST는 HTTP 표준에만 따른 다면, 어떠한 기술이라던지 사용이 가능한 인터페이스 스타일이다. HTTP + JSON으로 정의를 했다면, 안드로이드건, IOS건, C 기타 다른 언어에 종속 받지 않고 사용할 수 있는 느슨한 결함 형태의 구조다.
  2. 무상태성/스테이트리스(Stateless)
    • REST는 Representational State Transfer의 약어로 상태를 유지하지 않는 특징 중 하나이다. 상태가 있다 없다의 의미는 사용자나 클라이언트의 컨택스트를 서버쪽에 유지 하지 않는다는 의미로 HTTP Session과 같은 상태 정보를 저장하지 않으며 각 API 서버는 들어오는 요청만 메시지로 처리하면 된다.
  3. 캐싱(Cacheable)
    • REST의 큰 특징 중 하나는 기존의 HTTP라는 웹 표준을 그대로 사용하기 때문에 웹에서 사용하는 기존의 인프라를 그대로 활용이 가능하다. HTTP 기반의 로드 밸런서나 SSL은 물론이고 캐싱기능을 적용할 수 있다. 일반적인 서버등의 캐싱하는 것은 용량이나 성능 면에서 많은 장점을 가지고 올 수 있다. 구현은 HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-TAG를 이용하면 캐싱을 구현 할 수 있다. Client가 HTTP GET을 Last-Modified 값과 함께 보냈을 때, 컨텐츠가 변화가 없으면 Rest 컴포넌트는 304 Not modified를 리턴하면 Client는 자체 캐쉬에 저장된 값을 사용하면 된다.
  4. 자체 표현 구조(Self-descriptiveness)
    • REST API 자체가 매우 쉬워서 API 메시지 자체만 보고도 API를 이해할 수 있는 Self-descriptiveness 구조를 갖는다. 리소스와 메서드를 이용해서 어떤 메서드에 무슨 행위를 하는지를 알 수 있으며, 또한 메시지 포맷 역시 JSON을 이용해서 직관적으로 이해가 가능한 구조이다.
  5. 클라이언트 서버 구조(Client-Server 구조)
    • 근래에 들면서 재 정립되고 있는 특징 중의 하나는 REST가 클라이언트 서버 구조라는 것이다. REST 서버는 API를 제공하고 제공된 API를 이용해서 비즈니스 로직 처리 및 저장을 책임진다. 클라이언트 경우 사용자 인증이나 컨텍스트(세션, 로그인정보) 등을 직접 관리하고 책임지는 구조로 역할이 나뉘어 지고 있다. 이렇게 역할이 각각 확실하게 구분되면서, 개발관점에서 클라이언트와 서버에서 개발해야 할 내용들이 명확하게 되고 의존성도 줄어든다.
  6. 계층형 구조(Layered System)
    • 계층형 아키텍쳐 구조 역시 근래에 들어서 주목받기 시작하는 구조 인데 클라이언트 입장에서는 REST API만 호출 한다. 그러나 서버는 다중 계층으로 구성될 수 있다. 순수 비즈니스 로직을 수행하는 API 서버와 그 앞 단에 사용자인증(Authentication), 암호화(SSL), 로드밸런싱등을 하는 계층을 추가해서 구조상의 유연성을 둘 수 있는데 이는 근래에 들어서 마이크로 서비스 아키텍쳐의 api gate나 간단한 기능의 경우는 HAProxy나 Apache와 같은 Reverse Proxy를 이용해서 구현하는 경우도 있다.

REST 안티 패턴

1. GET/POST를 이용한 터널링
– http://localhost/users?method=update&id=wonwoo 이 경우가 전형적인 GET을 이용한 터널링이다. 메서드의 실제 동작은 리소스를 업데이트 하는 내용인데, HTTP PUT이나 PATCH를 사용하지 않고 쿼리파라미터로 method=update라고 넘겨서 수정 메서드임을 명시했다. 또 한 Insert성 오퍼레이션이 아닌데도 불구하고 JSON 바디에 오퍼레이션명을 넘기는 형태인데 예를 들어 특정 사용자 정보를 가지고 오는 API를 아래와 같이 POST를 이용해서 만든 경우이다.

HTTP POST, http://localhost/users
{
  "getuser": {
     "id" : "wonwoo"
  }
}

2. HTTP Response code를 사용하지 않음
– 다음으로 많이 하는 디자인 중 하나가 Http Response code를 충실하게 따르지 않고 성공은 200, 실패는 500과 같이 1~2개의 Http Response code만 사용하는 경우이다. 심한 경우에는 에러도 Http Response code 200으로 정의한후 별도의 에러 메시지를 200 Response code와 함께 보내는 경우이다.

출처: 조대협님 블로그(http://bcho.tistory.com/m/post/953)

Accept와 Content-type

Accept

  • 클라이언트가 서버에 어떤 형식(MediaType)으로 달라는 요청을 할 수 있는데 이게 Accpet 헤더를 뜻하는거다.

Content-Type

  • 클라이언트가 request에 실어 보내는 데이타(body)의 형식(MediaType)를 표현하는거다.