Java:基于注释的代码注入的简单技术?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1079343/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:05:26  来源:igfitidea点击:

Java: Simple technique for annotation-based code injection?

javaannotationsaop

提问by Robert Wilson

Is there a way to make this code work?

有没有办法让这段代码工作?

LogonControl.java

登录控件.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.

最终结果是,每次调用 login() 时,也会使用适当的审计类型调用 audit()。

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).

我想 AOP 可能是解决这个问题的方法,但我希望它尽可能简单(我看过的 AspectJ 教程通常有非常复杂的注释)。

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.

注意:我不想预先定义将调用审计的方法,我正在为可扩展框架编写它,其他人可能需要使用它。

回答by dfa

Using reflection is easy just annotate a method with @Audit, just like test runners in JUnit:

使用反射很容易,只需使用@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 is defined as:

@Audit 定义为:

@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

回答by duffymo

It's done - use Springor Guice.

完成了 - 使用SpringGuice

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.

如果您想知道轮子是如何工作的,或者如果您认为您可以做一些明显更轻的事情,那么自行滚动是有意义的。在您开始之前,请确保两者都是正确的。

回答by Esko Luontola

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

看看 Guice 中的拦截方法:http: //code.google.com/p/google-guice/wiki/AOP

A similar approach should work with any AOP framework.

类似的方法应该适用于任何 AOP 框架。