2009-07-03 4 views
4

Есть ли способ заставить этот код работать?Java: Простая техника для ввода кода на основе аннотаций?

LogonControl.java

@Audit(AuditType.LOGON) 
public void login(String username, String password) { 
// do login 
} 

AuditHandler.java

public void audit(AuditType auditType) { 
// persist audit 
} 

Endgame быть, что каждый раз, когда Логин() вызывается, аудит() также называется, с соответствующим audittype.

Я полагаю, что AOP, вероятно, является решением этого вопроса, но я хотел бы, чтобы он был как можно более простым (обучающие материалы AspectJ, на которые я смотрел, обычно имеют очень запутанные аннотации).

Примечание: я не хочу предопределять методы, которые будут вызывать аудит, я пишу это для расширяемой структуры, а другим, возможно, придется ее использовать.

+0

Что должен делать код? Должен ли метод audit() вызываться каждый раз, когда вызывается метод, который аннотируется с помощью @Audit? –

+0

@ Эско Луонтола - да, точно. –

ответ

14

С помощью отражения легко просто аннотировать метод с @Audit, так же, как тест бегунами в JUnit:

public interface Login { 

    void login(String name, String password); 
} 

public class LoginImpl implements Login { 

    @Audit(handler = LoginHandler.class) 
    public void login(String name, String password) { 
     System.out.println("login"); 
    } 

} 

@Audit определяется как:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface Audit { 

    Class<? extends Handler> handler(); 
} 

, где Обработчик:

interface Handler { 

    void handle(); 
} 

class LoginHandler implements Handler { 

    public void handle() { 
     System.out.println("HANDLER CALLED!"); 
    } 
} 

и теперь настоящий код:

public class LoginFactory { 

    private static class AuditInvocationHandler implements InvocationHandler { 

     private final Login realLogin; 

     public AuditInvocationHandler(Login realLogin) { 
      this.realLogin = realLogin; 
     } 

     public Object invoke(Object proxy, Method method, Object[] args) 
         throws Throwable { 
      Method realMethod = realLogin.getClass().getMethod(
             method.getName(), 
             method.getParameterTypes()); 
      Audit audit = realMethod.getAnnotation(Audit.class); 

      if (audit != null) { 
       audit.handler().newInstance().handle(); 
      } 

      return method.invoke(realLogin, args); 
     } 
    } 

    public static Login createLogin() { 
     return (Login) Proxy.newProxyInstance(
       LoginFactory.class.getClassLoader(), 
       new Class[]{Login.class}, 
       new AuditInvocationHandler(new LoginImpl())); 
    } 
} 

@Test:

Login login = LoginFactory.createLogin(); 
    login.login("user", "secret"); 
    login.logout(); 

выход:

 
HANDLER CALLED! 
login 
logout 
+0

Кажется, лучшее решение. Я надеялся сохранить мой код как есть и просто добавить аннотации, но после многих исследований я не думаю, что это возможно. Cheers. –

5

Это сделано - используйте Spring или Guice.

Роллинг имеет смысл, если вы хотите know how wheels work, или если вы думаете, что можете сделать что-то значительно легче. Просто убедитесь, что оба они верны, прежде чем предпринимать это.

+0

Поверьте мне - у меня нет желания кататься самостоятельно, но Spring - это OTT для моих целей. Я посмотрю на Guice, изначально это выглядит хорошо. –

+0

Могу сказать, что вам не нужно глотать ВСЕ весну, чтобы получить от этого выгоду. Spring AOP довольно легкий вес по сравнению с AspectJ (менее мощный, а также). Это может удовлетворить ваши потребности. Вам не нужно иметь дело со всей весной, просто небольшим подмножеством, которое относится к АОП. Я обнаружил, что Spring хорошо работает для этих ситуаций. Можно ввести его в устаревшее приложение для узкой цели, не требуя полной перезаписи. Попробуй. – duffymo

+0

В Spring уже есть встроенный трассировочный аспект. Возможно, вы сможете делать то, что хотите, с небольшой конфигурацией и без нового кода. – duffymo

1

Посмотрите на методы перехватывающих в Guice: http://code.google.com/p/google-guice/wiki/AOP

Аналогичный подход должен работать с любым АОП.

+0

Спасибо за это. Эта строка немного меня пугает: «Невозможно использовать перехват методов для экземпляров, которые не созданы Guice». Насколько я понимаю, это означало бы, что мне придется использовать Guice.getInstance (LogonController.class) до того, как будет запущен метод перехвата? Я рассмотрю, возможно ли это в другой структуре АОП. –

+0

Это означает, что Guice должен будет построить объект, но это не значит, что вам придется попросить Guice его построить. Объект может быть введен в другой объект, который построен Guice. По существу, Guice заменит Factory в решении, которое дал dfa. – NamshubWriter