Java googleguice中的条件匹配
我有一个绑定到类中方法的MethodInterceptor,以便在类接触数据之前对数据执行一些简单的逻辑。 然而,类本身会调用它自己截获的一些方法,但此时我不再需要重新运行该逻辑Java googleguice中的条件匹配,java,dependency-injection,aop,guice,Java,Dependency Injection,Aop,Guice,我有一个绑定到类中方法的MethodInterceptor,以便在类接触数据之前对数据执行一些简单的逻辑。 然而,类本身会调用它自己截获的一些方法,但此时我不再需要重新运行该逻辑 public class MyModule extends AbstractModule { @Override public void configure() { bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation
public class MyModule extends AbstractModule {
@Override
public void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), new MyInterceptor());
}
}
public class MyInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// logic
}
}
public MyClass {
@MyAnnotation
void foo() {
bar();
}
@MyAnnotation
void bar() {
}
}
有没有一种方法不允许在foo中调用bar?老实说,最简单的解决方案是通过从不在类中调用同一类的另一个公共/注释方法来避免问题:
public class MyClass {
@MyAnnotation
public void foo() {
doBar();
}
@MyAnnotation
public void bar() {
doBar();
}
private void doBar() {
//doesn't go through interceptor
}
}
如果出于某种原因,这不是一种选择,那么您可以考虑这种方法。更具表现力的AOP库(如AspectJ)为定义切入点提供了更大的灵活性
在Guice中,切入点只是一个方法,带有属于Guice实例化的实例的注释。所以这个逻辑必须转移到拦截器本身
这样做的一种方法可能是使用ThreadLocal
跟踪进入拦截器的条目。扩展这样的内容可能是一个开始:
public abstract class NonReentrantMethodInterceptor implements MethodInterceptor {
private final ThreadLocal<Deque<Object>> callStack = new ThreadLocal<>();
@Override
public final Object invoke(MethodInvocation invocation) throws Throwable {
Deque<Object> callStack = this.callStack.get();
if (callStack == null) {
callStack = new LinkedList<>();
this.callStack.set(callStack);
}
try {
return invokeIfNotReentrant(callStack, invocation);
} finally {
if (callStack.isEmpty()) {
this.callStack.remove();
}
}
}
private final Object invokeIfNotReentrant(Deque<Object> callStack, MethodInvocation invocation) throws Throwable {
Object target = invocation.getThis();
if (callStack.isEmpty() || callStack.peek() != target) {
//not being called on the same object as the last call
callStack.push(target);
try {
return doInvoke(invocation);
} finally {
callStack.pop();
}
} else {
return invocation.proceed();
}
}
protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
}
哇,太好了。幸运的是,前两个(也是更优雅的)解决方案很容易获得,但我确实认为你所建议的相当简洁。好吧,我的应用程序的结构方式,我可能可以做类似的事情,因为我只关心过滤第一个请求@Override public Object invoke(MethodInvocation invocation)抛出的Throwable{this.inProcess.get(),invocation.getMethod());整数inProcess=this.inProcess.get();尝试{if(inProcess==null){this.inProcess.set(1);return doInvoke(invocation);}else{this.inProcess.set(inProcess+1);return invocation.procement();}最后{this.inProcess.set(inProcess);}}}其中private final ThreadLocal inProcess=new ThreadLocal();
public class NonReentrantTester {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new Module());
MyClass instance = injector.getInstance(MyClass.class);
instance.foo();
}
static class Module extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrintsFirstInvocation.class),
new PrintsFirstInvocationInterceptor());
}
}
public static class MyClass {
@PrintsFirstInvocation
void foo() {
bar();
}
@PrintsFirstInvocation
void bar() {
}
}
public static class PrintsFirstInvocationInterceptor extends NonReentrantMethodInterceptor {
@Override
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod());
return invocation.proceed();
}
}
@BindingAnnotation
@Target({FIELD, PARAMETER, METHOD})
@Retention(RUNTIME)
public @interface PrintsFirstInvocation {
}
}