2009-07-03 6 views
4

Gibt es eine Möglichkeit diesen Code Arbeit zu machen?Java: Einfache Technik für die Annotation-basierte Code-Injektion?

LogonControl.java

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

AuditHandler.java

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

Endgame wird, dass jedes Mal, Login() aufgerufen wird, Audit() wird auch mit der entsprechenden audittype genannt.

Ich denke, AOP ist wahrscheinlich die Lösung, aber ich möchte es so einfach wie möglich (die AspectJ Tutorials, die ich mir angesehen habe, haben normalerweise sehr komplizierte Anmerkungen).

Hinweis: Ich will nicht die Methoden vordefinieren haben, die Prüfung nennen, ich dies für ein erweiterbares Framework zu schreiben, und andere müssen es benutzen.

+0

Was tun sollte der Code? Soll die Methode audit() jedes Mal aufgerufen werden, wenn eine Methode aufgerufen wird, die mit @Audit versehen ist? –

+0

@Esko Luontola - ja, genau. –

Antwort

14

Reflexion Verwendung ist einfach nur ein Verfahren, mit @Audit Anmerkungen versehen, ebenso wie Testläufer in 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 definiert ist als:

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

    Class<? extends Handler> handler(); 
} 

wo Handler ist:

interface Handler { 

    void handle(); 
} 

class LoginHandler implements Handler { 

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

und jetzt der echte Code:

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(); 

Ausgang:

 
HANDLER CALLED! 
login 
logout 
+0

Scheint wie die beste Lösung. Ich hatte gehofft, meinen Code unverändert zu behalten und nur Anmerkungen hinzufügen zu können, aber nach vielen Recherchen halte ich das nicht für möglich. Prost. –

5

Es ist geschafft - verwenden Spring oder Guice.

Roll Ihren eigenen macht Sinn, wenn Sie know how wheels work wollen, oder wenn Sie denken, dass Sie etwas tun kann, das ist deutlich leichter. Seien Sie sicher, dass beide wahr sind, bevor Sie es unternehmen.

+0

Vertrau mir - ich habe keine Lust, meine eigenen zu rollen, aber Frühling ist OTT für meine Zwecke. Ich schaue in Guice, zunächst sieht es gut aus. –

+0

Mein Punkt wäre, dass Sie müssen nicht alle Frühling schlucken Nutzen daraus zu ziehen. Spring AOP ist ziemlich leicht im Vergleich zu AspectJ (auch weniger leistungsfähig). Es könnte Ihren Bedürfnissen gerecht werden. Sie müssen sich nicht mit dem gesamten Spring befassen, nur mit der kleinen Teilmenge, die AOP betrifft. Ich habe festgestellt, dass Spring für diese Situationen gut funktioniert. Es ist möglich, es in eine Legacy-App für einen engen Zweck einzuführen, ohne eine vollständige Neuschreibung zu verlangen. Versuch es. – duffymo

+0

Im Frühling gibt es bereits einen eingebauten Trace-Aspekt. Sie können vielleicht mit einer kleinen Konfiguration und ohne neuen Code machen, was Sie wollen. – duffymo

1

Werfen Sie einen Blick auf das Abfangen Methoden in Guice: http://code.google.com/p/google-guice/wiki/AOP

Ein ähnlicher Ansatz sollte mit jedem AOP Framework arbeiten.

+0

Danke dafür. Diese Zeile macht mir ein wenig Angst: "Es ist nicht möglich, Methode Abfangen für Instanzen, die nicht von Guice erstellt werden." Nach meinem Verständnis würde dies bedeuten, dass ich Guice.getInstance (LogonController.class) verwenden müsste, bevor das Abfangen der Methode funktioniert? Ich werde prüfen, ob dies in einem anderen AOP-Framework möglich ist. –

+0

Es bedeutet, dass Guice das Objekt konstruieren muss, aber es bedeutet nicht, dass Sie Guice darum bitten müssen, es zu konstruieren. Das Objekt könnte in ein anderes Objekt injiziert werden, das von Guice konstruiert wird. Im Wesentlichen würde Guice die Fabrik in der Lösung ersetzen, die dfa gab. – NamshubWriter

Verwandte Themen