Ordering multiple RouterFunctions - spring

I have multiple RouterFunctions which I register as beans (one per section of code).
One of them is /** for dynamic routing for React. Basically, if no other route matches, I want it to go to that one.
The problem is sometimes, depending on the whims of what order they are used, the /** will block another endpoint.
Is there a way to order the separate RouterFunctions or a better way to deal with having everything that doesn't match something else go to a specific route?

Spring WebFlux is gathering all RouterFunction beans and reducing them into one using RouterFunction::andOther (See RouterFunctionMapping).
So you can just order your RouterFunction beans as regular beans and Spring WebFlux will do the rest.
#Bean
#Order(1)
public RouterFunction first() {
//
}
#Bean
#Order(2)
public RouterFunction second() {
//
}
#Bean
#Order(3)
public RouterFunction third() {
//
}

I've worked out a solution that takes advantage of the fact that RouterFunction has an add() function to combine them together.
First, I had RouterFunction beans that looked something like this:
#Configuration
class MyRouter {
#Bean
fun myRoutes(myHandler: MyHandler): RouterFunction<ServerResponse>
= router {
GET("/path", myHandler::handlePath)
}
}
I had multiple of these, and if there were some conflicting paths (like /**), which one ran was kind of question mark.
I decided to merge these into one RouterFunction where I could control the order. Since I didn't want to have to manually manage these somewhere (i.e., if I made a new Router class, I just wanted it picked up automatically).
First, I had to make my normal routes no longer beans. I also needed an easy way to let Spring find them all, so I decided to create an abstract class for them to extend.
That looked like this:
abstract class RouterConfig {
open val priority: Int = 0 // higher number, later in list
open val routes: RouterFunction<ServerResponse>
get() = TODO()
}
The priority lets me override the order they are added (with the default being fine if it doesn't matter). A larger number means it'll be loaded later.
After that, I changed my Router classes to Components and made them not spit out a bean anymore. Something like this:
#Configuration
class MyRouter(
private val myHandler: MyHandler
) {
override val routes: RouterFunction<ServerResponse>
get() = router {
GET("/path", myHandler::handlePath)
}
}
Finally, I create a new class and bean which would gather them all up:
#Configuration
class AppRouter {
#Bean
fun appRoutes(routerConfigs: List<RouterConfig>): RouterFunction<ServerResponse>
= routerConfigs.sortedBy { it.priority }
.map { it.routes }
.reduce { r, c -> r.add(c) }
}
And that seemed to do the trick. Now the routes will be added in priority order, so for the one that might be a bit greedy (/**) I simply set the priority of that class to 100 to make it come last.

Related

Spring: Configuration

In Spring Java configuration, suppose I want to re-use a #Bean in another #Bean definition. I can do this either in one file:
#Bean
public A buildA() {
return new A();
}
#Bean
public B buildB() {
return new B(buildA());
}
or I can configure A in one file and autowire it in another file like (field injection for brevity):
#Autowired
private A a;
#Bean
public B buildB() {
return new B(a);
}
I wonder, if the two possibilities are exactly the same? For me it looks as if, the first version might instatiate A twice, while the second doesn't.
I am asking this, since in my special use case, A is establishing a connection to a messaging broker and I have several Bs that consume the stream (I use .toReactivePublisher() from spring integration in A), and I don't want to connect twice or more to the broker.
Yes, they're exactly the same. Multiple calls to a #Bean annotated method will not create multiple instances of the same bean.
For an explanation on why it doesn't happen, please see this answer.

How to choose bean implementation at runtime for every http request

I am having two implementations of my component.
public interface MyComponent {
}
imple1
#Component("impCompf")
#Lazy
#RequestScope
public class ImpComp1 implements MyComponent {
}
imple2
#Component("impComps")
#Lazy
#RequestScope
public class ImpComp2 implements MyComponent {
}
What I did so far is to create two conditions like so:
imple1
public class FirstCondition implements Condition {
#Override
public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
return staticVariable.contains("impCompf");
}
}
Same goes for imple2
and define a configuration class
#Configuration
public class MyConfiguration {
#Bean
#Conditional(FirstCondition .class)
#Primary
public MyComponent getComp1() {
return new ImpComp1();
}
public static String staticVariable= "impCompf";
and in My main controller:
#RequestMapping(value="api/{co}", method=RequestMethod.POST)
public ResponseEntity<Modelx> postSe(#PathVariable("co") String co) {
if(co.contains("impCompf"))
staticVariable = "impCompf";
else (co.contains("impComps"))
staticVariable = "impComps";
What I want: for every http request I want to load proper implementation
But however what I am getting is the implementation defined first in the static variable.
If is there another elegant and better way, i'd like to know about it.
I think there is some confusion here about the purpose of the conditions. These aren't being used at the time your requests arrive to autowire the candidate bean into your controller. These are being used when the application is started to configure the application context based on the environment and classpath etc...
There is no need for the conditional classes that you have created. This is defining the configuration of the beans when the context starts and not on a per request basis at runtime.
The use of the static variable is also problematic is a scenario with one or more concurrent requests or in a case where multiple threads may observe different values unless some other mechanism in the java memory model is being used (such as volatile or establishing a happens before relationship, e.g. with sychnronized)
There are a number of ways to do what you appear to be trying to achieve. Since ultimately, you appear to be using a path parameter supplied by a client to determine which service you want to invoke you could use a classic factory pattern to return the correct interface implementation based on the string input programmatically.
Alternatively you could create two distinct controller methods which are distinguished by a query parameter or endpoint name or path match etc. You could then have the appropriate service injected by a qualified bean name
Although perhaps generally recommended, you could also inject an application context instance and search the it looking for the relevant bean by name or class: https://brunozambiazi.wordpress.com/2016/01/16/getting-spring-beans-programmatically/ - although This is more cumbersome and you'd need to handle things like org.springframework.beans.factory.NoSuchBeanDefinitionException or casting in some cases - best avoided in favour of one of the other methods.

How can I name a #Service with multiple names in Spring?

I need something like:
#Named({"bean1", "bean2"})
#Service({"bean1", "bean2"})
Can someone help me?
Not directly, the way you have it. But it is possible by redefining an existing #Service (or #Component) as a #Bean with either a name or list of names, it is possible.
#Service("Service-A")
public class SampleService {
public String doSomething() { return "Foo"; }
}
#Configuration
public class SampleConfig {
#Bean(name = {"Service-B", "Service-C"})
public SampleService createMirroredService(#Autowired SampleService service) {
return service;
}
}
And now you have three instances of SampleService: Service-A (your #Service), Service-B, and Service-C. This works because you define one and just have the #Bean annotated method pass through the implementation, which has the effect of creating aliases. Make sure the configuration class is picked up in the scan and it should work fine.
Note: Although this works, and there are probably other solutions as well, I can't think of a case where I would need this. Perhaps if I'm integrating with a library that already exists that I can't change. But there doesn't strike me as a serious need for this, or else they would have made value on #Component an array.
Though I think #Todd answer is totally correct. It seems it has mislead some others to follow the idea. See Autowire Map with custom class and use aliases to get the correct object reference.
Therefore I would like to add an answer here to suggest one to use the below methodology instead.
#Configuration
public class SampleConfig {
#Bean(name = {"Service-A", "Service-B", "Service-C"})
public SampleService createMirroredService() {
return new SampleService();
}
}
This would be much cleaner than the above answer, though may not answer the question properly.

Dependency Injection with Interface implemented by multiple classes

Update: Is there a way to achieve what I'm trying to do in an IoC framework other than Windsor? Windsor will handle the controllers fine but won't resolve anything else. I'm sure it's my fault but I'm following the tutorial verbatim and objects are not resolving with ctor injection, they are still null despite doing the registers and resolves. I've since scrapped my DI code and have manual injection for now because the project is time sensitive. Hoping to get DI worked out before deadline.
I have a solution that has multiple classes that all implement the same interface
As a simple example, the Interface
public interface IMyInterface {
string GetString();
int GetInt();
...
}
The concrete classes
public class MyClassOne : IMyInterface {
public string GetString() {
....
}
public int GetInt() {
....
}
}
public class MyClassTwo : IMyInterface {
public string GetString() {
....
}
public int GetInt() {
....
}
}
Now these classes will be injected where needed into layers above them like:
public class HomeController {
private readonly IMyInterface myInterface;
public HomeController() {}
public HomeController(IMyInterface _myInterface) {
myInterface = _myInterface
}
...
}
public class OtherController {
private readonly IMyInterface myInterface;
public OtherController() {}
public OtherController(IMyInterface _myInterface) {
myInterface = _myInterface
}
...
}
Both controllers are getting injected with the same interface.
When it comes to resolving these interfaces with the proper concrete class in my IoC, how do I differentiate that HomeController needs an instance of MyClassOne and OtherController needs an instance of MyClassTwo?
How do I bind two different concrete classes to the same interface in the IoC? I don't want to create 2 different interfaces as that breaks the DRY rule and doesn't make sense anyway.
In Castle Windsor I would have 2 lines like this:
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>());
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>());
This won't work because I will only ever get a copy of MyClassTwo because it's the last one registered for the interface.
Like I said, I don't get how I can do it without creating specific interfaces for each concrete, doing that breaks not only DRY rules but basic OOP as well. How do I achieve this?
Update based on Mark Polsen's answer
Here is my current IoC, where would the .Resolve statements go? I don' see anything in the Windsor docs
public class Dependency : IDependency {
private readonly WindsorContainer container = new WindsorContainer();
private IDependency() {
}
public IDependency AddWeb() {
...
container.Register(Component.For<IListItemRepository>().ImplementedBy<ProgramTypeRepository>().Named("ProgramTypeList"));
container.Register(Component.For<IListItemRepository>().ImplementedBy<IndexTypeRepository>().Named("IndexTypeList"));
return this;
}
public static IDependency Start() {
return new IDependency();
}
}
I hope you can use service overrides.
Ex.
container.Register(
Component.For<IMyService>()
.ImplementedBy<MyServiceImpl>()
.Named("myservice.default"),
Component.For<IMyService>()
.ImplementedBy<OtherServiceImpl>()
.Named("myservice.alternative"),
Component.For<ProductController>()
.ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.alternative"))
);
public class ProductController
{
// Will get a OtherServiceImpl for myService.
// MyServiceImpl would be given without the service override.
public ProductController(IMyService myService)
{
}
}
You should be able to accomplish it with named component registration.
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>().Named("One"));
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>().Named("Two"));
and then resolve them with
kernel.Resolve<IMyInterface>("One");
or
kernel.Resolve<IMyInterface>("Two");
See: To specify a name for the component
Typically DI containers follow Register, Resolve and Release patterns. During the register phase there are two steps. The first is to specify the mapping as you are doing. The second step is to specify the rules which govern which to inject where.
This problem is very common when we try to address Cross cutting concerns using decorators. In these situations, you have multiple classes(decorators) implementing a single interface.
Briefly, we need to implement IModelInterceptorsSelector which allows you to write imperative code that decides which Interceptor to apply to which types or members.
This is elaborately described in the book Dependency Injection in .Net book by Mark Seemann. Look for chapter 9 interception or search for the above interface.
I am not an expert at this, but was searching for the exact same problem and found the ans in the above book.
Hope this helps.
Regards
Dev1

How to Produce prototype objects from singleton? (Design help needed)

I'm relatively new to Spring and I've got myself dug in a hole. I'm trying to model motor cars. Each model has it's own builder object, and I have a BuilderFactory that returns the correct builder based upon user selection from a web-app.
So I'm looking for suggestions on how to approach this problem where I need to create a number of individual vehicles, but I don't know what type of vehicle I'm going to need until run-time, and each vehicle needs to be unique to the user.
What I've got at the moment is shown below. The problem I have at the moment is that because the individual builders are singletons so are the individual vehicles. I need them
to be prototypes. I know it all looks pretty horrible so I'm sure there must be a better way of doing this.
The top level from the web-app looks like;
Vehicle vehicle = vehicleBuilderFactory.getBuilder(platform).build();
My vehicleBuilderFactory looks like this;
#Service
public class VehicleBuilderFactory {
#Autowired
Discovery3Builder discovery3Builder;
#Autowired
Discovery4Builder discovery4Builder;
// Lots of #Autowired statements here.
#Autowired
FreeLander2010Builder freeLander2010Builder;
public VehicleBuilder getBuilder(Platform platform) {
switch (platform.getId()) {
case 1: return discovery3Builder;
case 2: return discovery4Builder;
// Lots of case statements here
case 44: return freeLander2010Builder;
default: return null;
}
}
}
which itself looks pretty horrible. Each individual builder looks like;
#Service
public class DefenderBuilder implements VehicleBuilder {
#Autowired
Defender defender;
// Loads of Defender specific setters ommitted
#Override
public Vehicle build() {
return defender;
}
}
and finally the individual vehicle
#Service
#Scope("prototype")
public class Defender extends Vehicle {
}
The main problem now, is that because the builders are singletons, so are the vehicles, and
I need them to be prototypes, because User A's Defender is different to user B's Defender.
You can use Spring's ObjectFactory to have it service up prototype scoped beans from a singleton scoped bean. The usage is pretty straightforward:
#Component
class DefenderBuilder implement VechicleBuilder {
#Autowired
ObjectFactory<Defender> defenderFactory;
Defender build() {
return defenderFactory.getObject()
}
}
#Component
#Scope("prototype")
class Defender {
}
This returns a new Defender on each call to defenderFactory.getObject()
Without reading too much into the detail you say you want to produce Prototype beans from a singleton possibly with a look up in the IoC container.
Section 3.4.6.1 Lookup method injection of the Spring documentation describes how this can be done without losing the Inversion of Control i.e. without your beans knowing about the bean store.
I have made use of the ServiceLocatorFactoryBean to solve a similar problem before. The class level Javadoc is excellent and contains some clear examples.
Two things:
1) You can use proxy in order to hold narrower scope from wider scope(e.g prototype from singleton)
All you need is to define the prototype component with the relevant scope and proxyMode
You can read about scoped proxy here.
2) Another thing that I have noticed is that you plan to use multiple autowired annotation.
note that you can use autowire on a list of interface and it will autowire all components that implements this interface as discussed here.
Moreover you can add a platform id to the VehicleBuilder interface and then generate a map in the constructor e.g:
Map<Integer, VehicleBuilder> vehicleBuilders;
#Autowired
public VehicleBuilderFactory(List<VehicleBuilder> vehicleBuilders) {
this.vehicleBuilders = vehicleBuilders.stream()
.collect(Collectors(x -> x.getPlatformId(), x -> x));
}
in that way you can avoid the switch case.

Resources