Choose Controller Bean instance by RequestMapping

Tags: , ,



I want Spring to create 2 instances of FooController. Requests to /foo should be handled by one of the instances and requests to /bar should be handled by the other instance. I want something like the below, but of course @RequestMapping doesn’t work that way and also Spring gives me the ambiguous mapping error on FooController as well.

@RestController
public class FooController {
  String name;
  public FooController(String name) { this.name = name; }
}

@Configuration
public class FooControllerConfig {
  @Bean
  @RequestMapping("/foo")
  public FooController getFooFooController(){
    return new FooController("foo");
  }
  @Bean
  @RequestMapping("/bar")
  public FooController getBarFooController(){
    return new FooController("bar");
  }
}

Answer

Don’t try this at home. This code was performed by a bored, trained professional…

You can have multiple instances of the same controller class, each of which handles a different URL through the same or a different method in the controller. The only thing is, I don’t know how to do it with just annotations. The way I just did it was to dynamically register each request mapping at initialization time. The FooController becomes a prototype bean (defined with annotations) so you can have Spring instantiate it multiple times, once for each mapping

FooController.java

@Controller
@Scope("prototype")
public class FooController {

    private String name;

    public FooController() {}

    public FooController(String name) {
        this.name = name;
    }

    public ResponseEntity<String> handleRequests() throws Exception {
        return new ResponseEntity<>("Yo: " + name + " " + this.hashCode(), HttpStatus.OK);
    }

EndpointService.java

@Service
public class EndpointService {

    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    public void addFooController(String urlPath, String name) throws NoSuchMethodException {

        RequestMappingInfo requestMappingInfo = RequestMappingInfo
                .paths(urlPath)
                .methods(RequestMethod.GET)
                .produces(MediaType.APPLICATION_JSON_VALUE)
                .build();

        requestMappingHandlerMapping.registerMapping(requestMappingInfo,
                beanFactory.getBean(FooController.class, name),
                FooController.class.getDeclaredMethod("handleRequests"));
    }

    @EventListener
    public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) {
        try {
            addFooController("/blah1", "blahblah1");
            addFooController("/blah2", "blahblah2");
            addFooController("/blah3", "blahblah3");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

Results:

http://localhost:8080/blah1 returns: Yo: blahblah1 1391627345

http://localhost:8080/blah3 returns: Yo: blahblah3 2078995154


Source: stackoverflow