Java: Simple technique for annotation-based code injection?

时光怂恿深爱的人放手 提交于 2019-12-30 01:29:45

问题


Is there a way to make this code work?

LogonControl.java

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

AuditHandler.java

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

Endgame being, that each time login() is called, audit() is also called, with the appropriate audittype.

I imagine AOP is probably the solution to this, but I would like it to be as simple as possible (the AspectJ tutorials I've looked at normally have very convoluted annotations).

Note: I don't want to have to predefine the methods that will call audit, I'm writing this for an extensible framework, and others may need to use it.


回答1:


Using reflection is easy just annotate a method with @Audit, just like test runners 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 is defined as:

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

   Class<? extends Handler> handler();
}

where Handler is:

interface Handler {

    void handle();
}

class LoginHandler implements Handler {

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

and now the real 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();

output:

HANDLER CALLED!
login
logout



回答2:


It's done - use Spring or Guice.

Rolling your own makes sense if you want to know how wheels work, or if you think that you can do something that's significantly lighter. Just be sure that both are true before you undertake it.




回答3:


Have a look at intercepting methods in Guice: http://code.google.com/p/google-guice/wiki/AOP

A similar approach should work with any AOP framework.



来源:https://stackoverflow.com/questions/1079343/java-simple-technique-for-annotation-based-code-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!