2010-06-12 3 views
3

나는 logAnotherAction비슷한 기능을 Java의 여러 메소드에 추가하려면 어떻게합니까?

지금 나는이 모든 방법이 인쇄 메시지 (Thread.sleep를) 후 작은 일시을 원하는, logSomeAction 같은 로깅 방법을 많이 가지고 있어요. 내가 수동으로 할 경우

, 내가 이런 짓을 할 것이다 :

//before: 
public static void logSomeAction() { 
    System.out.println (msg(SOME_ACTION)); 
} 

//after: 
public static void logSomeAction() { 
    System.out.println (msg(SOME_ACTION)); 
    try { 
     Thread.sleep (2000); 
    } catch (InterruptedException ignored) { } 
} 

나는 자바 프록시 클래스와 다른 마법을 만드는 도구가 있음을 기억하십시오. 어떤 방법으로 N 개의 기록 방법에 N 개의 수면 블록을 복사하여 붙여 넣는 것을 피할 수 있습니까?

답변

7

Aspects을 사용하면 메서드에 "직교 (orthogonal)"기능을 추가 할 수 있습니다.

너무 익숙하지 않은 경우 간단하고 실용적인 솔루션은 별도의 메서드에 절전 모드를 추가 한 다음 각 메서드의 각 메서드에서 해당 메서드를 호출하는 것입니다. 처음이 작업을 수행 할 때 각 방법을 터치해야하지만 다음 번에 추가 동작을 수정하거나 다른 것을 추가하려면 한 곳에서 수행 할 수 있습니다.

+1

나는 측면을 싫어하는 것과 마찬가지로, 이것이 바로 그들이하는 일입니다. 애스펙트는 표준 Java 구현의 일부가 아니기 때문에 별도의 컴파일러를 사용해야합니다. [AspectJ] (http://www.eclipse.org/aspectj/)는 Java의 공통된 부분입니다. –

+0

저는 aspect에 대한 아이디어가 마음에 들었고, 저는 Spring의 측면에 대해서도 배웠습니다. 그러나 나는 아직이 해결책을 스스로하기에 충분한 지식이 없지만 그 일을 끝내야한다. 적절한 코드를 가지고 있습니까? 아니면 최소한 sscce입니까? 의존성이 해결되어야 하는가? – Roman

+0

애스펙트에는 편집기에 표시되는 코드가 반드시 실행중인 코드 일 필요는 없다는 단점이 있습니다. –

0

try ... catch 블록을 포함하는 정적 인 SleepFor 메서드를 가진 유틸리티 클래스를 만들고 잠자기하고 싶은 모든 메서드에서 호출하십시오.

2

Aspect Oriented Programming을 사용하려는 것 같습니다. Spring을 AOP, AspectJ 용으로 사용할 수있다.

+0

아니요, 아닙니다. 나는 평범한 구식 프록시를 사용하고 싶다. http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html하지만 구문을 기억하지 못하고 나는 그들과 충분한 경험이 없다. btw, AOP는 또한 프록시 (아마도 다른 프록시 구현이지만 생각은 동일합니다)를 사용합니다. – Roman

+0

스프링 AOP 예,하지만 AspectJ 않습니다 (바이트 코드 - 제직을 사용하고 있습니다) – Arjan

0

모든 System.out.println (msg (SOME_ACTION)); 와 printAndWait (SOME_ACTION); 찾기 및 바꾸기를 통해이를 수행 할 수 있어야합니다. 는 그런 방법

public static void printAndWait(Object someAction) { 
    System.out.println (msg(someAction)); 
    try { 
     Thread.sleep (2000); 
    } catch (InterruptedException ignored) { 
     Thread.currentThread.interrupt(); 
    } 
} 

에게 코드가 한 번 나타납니다 그 방법을 작성하고 한 곳에서 쉽게 변경할 수 있습니다.

0

logSomeAction() 메서드를 모두 logAction(Action a) 메서드로 바꿉니다. 이렇게하면 나중에 더 많은 작업을 추가 할 때 작업 로그 및 스레드 잠을 처리하기위한 코드를 반복하지 않게됩니다.

1

OP는 일반 자바 프록시를 사용하는 것이 가장 좋은 해결책이라는 의견을 언급합니다. 현재 코드는 정적 메소드로 구현됩니다. Java 프록시를 사용하기 위해서는 로거 클래스를 인터페이스로 재 작성해야합니다. 이런 식으로 뭔가 :

public interface SomeActionLogger 
{ 
    void logSomeAction(); 
    void logSomeOtherAction(); 
    // etc.. 
} 

당신은 다음 만들고, 구체적인 구현 그런 다음 가질 수

public class SystemOutActionLogger implements SomeActionLogger 
{ 
    public void logSomeAction() { 
     System.out.println (msg(SOME_ACTION)); 
    } 
} 

자바 프록시는

class DelayAfterInvocationHandler implements InvocationHandler 
{ 
    private Object delegate; 
    private int duration; 

    DelayAfterInvocationHandler(Object delegate, int duration) 
    { 
     this.delegate = delegate; 
     this.duration = duration; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
     Object returnValue = method.invoke(delegate, args); 
     Thread.sleep(duration); 
     // you may want to catch InterruptedEception 
     return returnValue; 
    } 
} 

이-소위하지의 일부를 숨길 수있는 SomeActionLogger 인터페이스를 포장 예쁜 프록시 코드를 사용하면 로거를 래핑하여 지연을 생성하는 메소드를 가질 수 있습니다.

public ActionLogger addDelay(SomeActionLogger logger, int delay) 
{ 
    return (ActionLogger)Proxy.newProxyInstance(
     impl.getClass().getClassLoader(), 
     new Class[] { SomeActionLogger.class }, 
     new DelayAfterInvocationHandler(logger, delay)); 
} 

그래서 당신은 다음 DelayInvocationHandler 로깅 인터페이스에 직교 것을

SomeActionLogger log = addDelay(new SystemOutActionLogger(), 2000); 

주 쓰기 - 그것은 어떤 인터페이스에 지연을 추가 할 수 있습니다. 그런 다음 일반 포장 방법을 다음과 같이 만들 수 있습니다.

public <T> T addDelay(T delegate, int delay, Class<T> interfaceType) 
{ 
    return (T)Proxy.newProxyInstance(
     delegate.getClass().getClassLoader(), 
     new Class[] { type }, 
     new DelayAfterInvocationHandler(delegate, delay)); 
} 
관련 문제