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
Java: Simple technique for annotation-based code injection?
提问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.
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 框架。

