程序的完整结构
注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UserAnnotation {
}
然后创建了一个拦截器:
public class UserInterceptor implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(UserInterceptor.class);
@Inject
UserService userService; // this is not working
public Object invoke(MethodInvocation invocation) throws Throwable {
logger.info("UserInterceptor : Interceptor Invoked");
Object result = invocation.proceed();
Observable<List<User>> observable = (Observable<List<Sample>>) result;
observable.flatMap(Observable::from).subscribe(object -> {
User user = (User)object
SampleSender sender = new SampleSender();
sender.setBoolean(user.isBoolean());
logger.info("Pushing Data into Sender");
userService.insert(String.join("_", "key", "value"), sender);
}
return result;
}
}
然后我创建了一个GuiceModule,如下所示:-
public class UserModule extends AbstractModule {
@Override
protected void configure() {
SampleInterceptor interceptor = new SampleInterceptor()
requestInjection(interceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(SampleAnnotation.class), interceptor);
}
}
我正在使用上述注释的类是
// This class also have so many method and this was already declared and using in another services, I created a sample class here
class UserClassForInterceptor {
@Inject
AnotherClass anotherClass;
// this userMethod() is not a new method, its already created,
// now I am adding annotation to it, because after finishing this functionality,
// I want something should be done, so created annotation and added here
@UserAnnotation
public Observable<List<Sample>> userMethod() {
logger.info("This is printing only once");
return anotherClass.getUser().flatMap(user ->{
logger.info("This is also printing twice");
// this logger printed twise means, this code snippet is getting executed twise
});
}
}
public class AnotherClass{
public Observable<User> getUser(){
Observable<Sample> observableSample = methodReturnsObservableSample();
logger.info("Getting this logger only once");
return observableSample.map(response-> {
logger.info("This logger is printing twice");
//here have code to return observable of User
});
}
}
如果我删除可观察对象内部的注释记录器,则仅打印一次,但是当我使用注释时,这些记录器将按时打印。为什么我不知道这样的行为。
我有一个RestModule
,使用它绑定UserClassForInterceptor
如下
public final class RestModule extends JerseyServletModule {
// other classes binding
bind(UserClassForInterceptor.class).in(Scopes.SINGLETON);
// other classes binding
install(new SampleModule());
}
现在我有一个bootsrap类,其中绑定了RestModule
public class Bootstrap extends ServerBootstrap {
binder.install(new RestModule());
}
用法:-
@Path("service/sample")
public class SampleRS {
@Inject
UserClassForInterceptor userClassForInterceptor;
public void someMethod() {
userClassForInterceptor.sampleMethod();
}
}
答案 0 :(得分:1)
您创建了一个注释@UserAnnotation
,以及一个与该注释一起使用的拦截器类。您将注释附加到方法userMethod()
。
拦截器例程所做的第一件事是调用userMethod()
以获取它返回的观察值,然后拦截器订阅到返回的观察值,从而导致出现第一条日志消息。最终,拦截器将可观察对象返回给原始调用者。当其他人订阅了返回的observable时,观察者链又被激活,因此日志消息出现两次。
RxJava有副作用
尽管RxJava是“功能性反应式编程”概念的实现,但您构造(以功能性方式)构造的观察者链仅在被订阅时才起作用,并且这些订阅具有副作用。记录输出是一个副作用,可能是最有益的。变量的更改或具有副作用的方法的调用具有更广泛的影响。
(适当地)构造观察者链时,它将充当潜在的计算,直到有订阅者为止。如果您需要拥有多个订阅者(对于您的问题域可能是这样),则必须决定是否需要为每个订阅(正常情况)激活观察者链,或者对于所有重叠的订阅只激活一次。
如果希望所有重叠的订阅共享相同的可观察对象,则可以使用share()
运算符。有许多相关的运算符会影响可观察项和订阅的生存期。以下是概述:How to use RxJava share() operator?
面向方面的编程:拦截器和Guice
您的代码正在使用Guice提供一种称为“面向方面的编程”的功能。这使您可以将代码引入程序中,以解决跨领域的问题,或者通过设置受控网关来增强其功能。使用Guice或类似的AOP方法需要纪律。
在您的情况下,您通过订阅具有非平凡副作用的观察者链,使用了拦截过程来导致无法解释的(直到现在)副作用。想象一下,您截获的方法建立了一个一次性连接,而拦截器用尽了该连接以完成其工作,而原始调用方则无法使用该连接。
您需要的纪律是了解拦截器必须遵循的规则。想想诸如“首先,不要伤害”之类的规则。
以FRP方式做事
如果在处理用户信息时需要添加一个额外的步骤,则应该在拦截器中构造一个新的可观察对象,该操作必须做到这一点,但前提是原始调用方订阅了该可观察对象:
Object result = invocation.proceed();
Observable<List<User>> observable = (Observable<List<Sample>>) result;
Observable<List<User>> newObservable = observable
.doOnNext( sampleList ->
Observable.fromIterable( sampleList )
.subscribe(object -> {
User user = (User)object
SampleSender sender = new SampleSender();
sender.setBoolean(user.isBoolean());
logger.info("Pushing Data into Sender");
userService.insert(String.join("_", "key", "value"), sender);
}));
return newObservable;
通过返回修改后的观察者链,您不会引入原始观察者链的副作用,并确保您在自己的代码中引入的副作用将仅被触发链已订阅。
答案 1 :(得分:0)
这段代码对我也有帮助
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = null;
try{
logger.debug("Interceptor Invoked");
result = invocation.proceed();
Observable<List<User>> observable = (Observable<List<User>>)result;
return observable
.doOnNext(this::updateUser);
}
catch(Exception ex){
logger.error("Error: ",ex);
}
return result;
}
private void updateUser(List<User> users) {
if(CollectionUtils.isNotEmpty(users)) {
for(User user: users) {
SampleSender sender = new SampleSender();
sender.setBoolean(user.isBoolean());
logger.info("Pushing Data into Sender");
userService.insert(String.join("_", "key", "value"), sender);
}
}
}