Scenario
We need to call a remote service in Filter to get the address of the service that load balance can call later.
Solution
@Activate(group = { CommonConstants.CONSUMER })
public class DeviceSelectorFilter implements Filter {
public DeviceSelectorFilter(ApplicationModel model) {
// Get Extension that contain Spring Application Context.
SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(
model
);
// Now you get Spring Application Context.
var applicationContext = springExtensionInjector.getContext();
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation)
throws RpcException {
// YOUR BUSNIESS LOGIC
}
}
I use JDK-17, If you are using JDK-1.8.0, replace [var] to target class.
Constructor Instantiates
The Dubbo framework instantiates the filter itself, therefore interfaces related to Spring (such as BeanFactoryAware) are not supported. However, Dubbo provides injectable objects that must implement ScopeModel. such as :
org.apache.dubbo.rpc.model.ApplicationModel
org.apache.dubbo.rpc.model.FrameworkModel
org.apache.dubbo.rpc.model.ModuleModel
Other types do not support constructor injection. more details in org.apache.dubbo.common.beans.support.InstantiationStrategy Class.
@SuppressWarnings("unchecked")
public <T> T instantiate(Class<T> type) throws ReflectiveOperationException {
// HIDE SOME CODE.
// 2. use matched constructor if found
List<Constructor<?>> matchedConstructors = new ArrayList<>();
Constructor<?>[] declaredConstructors = type.getConstructors();
for (Constructor<?> constructor : declaredConstructors) {
// HERE! CHECK Constrcutor Arguments Object must implement ScopeModel!!!
if (isMatched(constructor)) {
matchedConstructors.add(constructor);
}
}
// HIDE SOME CODE
// create instance with arguments
Class<?>[] parameterTypes = targetConstructor.getParameterTypes();
Object[] args = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
// get target scopeModel object.
args[i] = getArgumentValueForType(parameterTypes[i]);
}
return (T) targetConstructor.newInstance(args);
}
private boolean isMatched(Constructor<?> constructor) {
for (Class<?> parameterType : constructor.getParameterTypes()) {
if (!isSupportedConstructorParameterType(parameterType)) {
return false;
}
}
return true;
}
private boolean isSupportedConstructorParameterType(Class<?> parameterType) {
return ScopeModel.class.isAssignableFrom(parameterType);
}
}
Try Get BeanFactory by ApplicationModel
ApplicationModel has getBeanFactory() method. but it return ScopeBeanFactory , that is internal BeanFactory of Dubbo, not Spring BeanFactory. ScopeBeanFactory contains only objects instantiated by dubbo itself, not objects from the spring BeanFactory.
THIS WAY IS DEAD END
org.apache.dubbo.rpc.model.ScopeModel
public abstract class ScopeModel implements ExtensionAccessor {
private volatile ScopeBeanFactory beanFactory;
public ScopeBeanFactory getBeanFactory() {
return beanFactory;
}
}
Thanks
Very thankful of Dubbo Community's Liu Jun, Thanks !
Scenario
We need to call a remote service in Filter to get the address of the service that load balance can call later.
Solution
Constructor Instantiates
The Dubbo framework instantiates the filter itself, therefore interfaces related to Spring (such as BeanFactoryAware) are not supported. However, Dubbo provides injectable objects that must implement ScopeModel. such as :
org.apache.dubbo.rpc.model.ApplicationModelorg.apache.dubbo.rpc.model.FrameworkModelorg.apache.dubbo.rpc.model.ModuleModelOther types do not support constructor injection. more details in
org.apache.dubbo.common.beans.support.InstantiationStrategyClass.Try Get
BeanFactorybyApplicationModelApplicationModelhasgetBeanFactory()method. but it returnScopeBeanFactory, that is internal BeanFactory of Dubbo, not Spring BeanFactory.ScopeBeanFactorycontains only objects instantiated by dubbo itself, not objects from the springBeanFactory.THIS WAY IS DEAD END
org.apache.dubbo.rpc.model.ScopeModelThanks
Very thankful of Dubbo Community's
Liu Jun, Thanks !