Set Spring MVC Paths in Java Config - java

Can Spring MVC paths be set as Java config, rather than using annotations on the controller?
I want to re-use one controller class under different path mappings, and have each instance wired with different service implementations.
For example, the API will look a bit like this:
PUT /mysql/some_key/some_value
GET /mysql/some_key
DELETE /mysql/some_key
PUT /oracle/some_key/some_value
GET /oracle/some_key
DELETE /oracle/some_key
So there'd be one instance of the controller wired with a MySqlCrudService and one instance of the controller with an OracleCrudService.
How would one configure this? The controller could have the methods annotated (eg #RequestMapping(method=RequestMethod.PUT, value="/{key}/{value}"), but when constructing the controller in Java config I'd need to specify the class-level path mapping.

Related

Order of Configuration in SpringBoot

I am trying to understand how beans that we make using #Configuration tends to override the beans that are generated by SpringBoot by default. I have been working on a project where in many cases we create beans for things like ZuulConfigs and the assumption is, whatever we are making shall take precedence over the default generated bean. I have been trying to figure this out but can't. Basically,
Is Spring achieving this via some custom class loader
If not how is this precedence working. Can I give some precedence in similar manner to my beans
Can I generate similar hierarchy in my project,if so how
The help is highly appreciated
Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.
If you want to configure the order in which beans are instantiated by spring you can use
#DependsOn("A")
public class B {
...
}
This would create bean "A", then "B". Hence you can order the configuration depending upon the beans need first to be done. Anyways Spring automatically detects the dependencies by analyzing the bean classes.
for more help check this question
Spring Boot AutoConfiguration Order
Alternative :
There is also "#AutoConfigureOrder" annotation(where you can prioritise the configuration), you can have a look in the code for deeper understanding.
Documentation of AutoConfiguration is here
First of all, class loading and bean creation are two different things. We don't need to create a bean to load a class, however, a class has to be loaded in order to create a bean.
Now, coming back to Spring's example, Spring looks into all the packages configured by #componentScan and creates beans of all the classes annotated with #Bean, #Configuration and/or #Component. Spring's container keeps track of all the beans created and hence, when it encounters user defined bean with same name and class type as default bean, it replaces the original definition with user defined one (e.g. we can create our custom #ObjectMapper to override Spring boot's own instance). You can also use #Primary annotation to make you bean take precedence if another definition with same class exists (documentation here).
Below are the answers for your questions:
Spring uses reflection to load the classes and create instances. Although you can load the classes with your custom class loader (more on that here), you don't need to worry about it for #Configuration.
Yes, you can use #Primary annotation to give your bean a precedence. You can also use #Order(here) to define the creation order for your beans.
With #Primary, #Order and #Qualifier annotation you can define your own hierarchy for bean creation.
Can I give some precedence in similar manner to my beans
Yes.
A) To define a specific order your Configuration classes will be handled (by the way, a Configuration class does not have to be annotated with #Configuration (so-called full definition), but it's enough to be annotated with #Component, #ComponentScan, #Import, #ImportResource or just have a method annotated with #Bean - so-called lite definition), you should
1) add your Configuration Candidates to your SpringApplication's primarySource, for example, in your main method like that
SpringApplication.run(
new Class[]{YourSpringBootApplication.class, Config1.class, Config2.class, ...},
args);
2) and annotate each of your Configuration Candidates with #Order annotation, any other ordering means like Ordered interface, #DependsOn etc will be ignored by ConfigurationClassPostProcessor, the order in the primarySource array will also be ignored.
Then ConfigurationClassPostProcessor will sort your Configuration Candidates and handle them according the #Order annotation value you specified.
B) The precedence can also be achieved by defining your own AutoConfiguration classes. Although both Configuration and AutoConfiguration are handled by the same ConfigurationClassPostProcessor, they are essentially distinctive machineries. To do so
1) define in your classpath /META-INF/spring.factories file and put in the EnableAutoConfiguration section of it your AutoConfiguration classes like that
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
your.package.AutoConfig1,your.package.AutoConfig2
2) and annotate your AutoConfiguration classes with #AutoConfigureOrder, #AutoConfigureAfter, or #AutoConfigureAfter annotations, any other ordering means again will be ignored.
Like #Strelok pointed out, AutoConfiguration classes, your own and provided e.g. by spring-boot-autoconfigure library alike, will be added to the end of the list of Configuration Candidates.
Remember, however, that the order the Configuration Candidates will be handled by ConfigurationClassPostProcessor does not necessarily coincide with the order the beans defined by the Configuration classes will be created. For example, you might define your Configuration class that overrides TomcatServletWebServerFactory to make your own customization of Tomcat web server like
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatServletWebServerFactory containerFactory() {
...
return customizedTomcatWebServerFactory;
}
but this method will be called right at the moment when your Spring Boot application decides to create a Web server, regardless of how you defined the precedence for your EmbeddedTomcatConfig Configuration class.
Is Spring achieving this via some custom class loader
There is no need to. Although you could, as always with Spring, define your own ClassLoader for BeanFactory, standard ClassLoader is good enough if everything you need for Configuration in your application is available in the classpath. Please notice, that at first phase ConfigurationClassPostProcessor does not load (i.e. does not resolve) the Configuration candidates classes (otherwise, most of the classes in spring-boot-autoconfigure library will fail to load). Instead it analyzes their annotations with bytecode analyzer, ASM by default. For that purpose, it is just enough to get a binary form, a byte array, of a class to feed it to bytecode analyzer.
Just know this: Spring Boot (specifically) auto configuration classes are always configured last. After all user beans have been created. Spring Boot auto configuration classes almost always use the #ConditionalXXXX annotations to make sure that any beans of the same type/name and other conditions that are configured in your application will take precedence over the Spring Boot auto-configured beans.
If you want your #Component to take precedence over other #Component while scanning all the components by spring, use #Order(Ordered.LOWEST_PRECEDENCE) i.e. the max value to load your component over other.
#Primary is used to give your bean a default preference, we can override the default preference using #Qualifier

How spring controller class object instantiated?

I have a question that, i have a spring-mvc based project which is accessible by multiple user. My question is that when more than one user access that application then for each user there is separate controller class object or all user access the same controller class object.
There will be multiple controller instances for different requests.
Please read:
http://docs.spring.io/spring-framework/docs/2.5.x/reference/mvc.html
Related answer:
How does Spring MVC handle multiple users
If the controller is a bean (which is the usual case) then the default is one bean per Spring container context.
If you set the controller/bean to scope=prototype then you would get a new instance from the factory each time.

Spring auto inject with constructor via code or annotations

Given having next classes:
XRepository with declared a constructor with 1 argument (simple one,
not autowired), it has some autowired fields.
XService that uses XRepository as autowired.
XProcessor uses XService as autowired.
So I have to init XProcessor on runtime for specific value that will be used in XRepository constructor. On different calls I will have different arguments, so the injection should be on runtime.
Any idea how to achieve that using code configuration or annotations?
Remember that Spring needs to inject all the constructor parameters of Spring managed beans.
I believe you have two options:
Parse your URL info in controller and pass it through parameters down to persistence layer. This would be my preferred mechanism. You can create special DTO for passing various information down and keep your method signatures concise.
Your situation can alos be solved with request scope bean. You will
create one bean like this:
#Component
#Scope("request")
public class {
private String urlPart;
}
And you would autowire this component into XProcessor and
XRepository. Each request to your application will create new
instance of XRequestContext and you will parse your info in
XProcessor and store it into XRequestContext.
In XRepository you will use instance of XRequestContext to
retrieve information you stored in XProcessor.
You can read about request scope in Spring docs. It is like
ThreadLocal per request thread.

Spring 4 conditional - Accessing a resource

Doing my first steps with spring 4 I tried the #Conditional annotation following this article.
My problem -
I would like to get access to a classpath resource (basically a properties file) from method matches in class OnSystemPropertyCondition.
To do that currently I'm loading the required properties file from the matches method every time it is invoked (which means for every class annotated with the ConditionalOnSystemProperty annotation).
This is a bit ugly. I thought that an elegant solution would be to simply autowire my resource or some properties (using the #Value annotation) but this can't be done since this class gets instanciated before the beans.
Any suggestions than can help me avoid reload this resource again and again?
The single method of the annotation gets in its signature the input param ConditionContext context. You can obtain an Environment from the context by calling context.getEnvironment(). The environment gives access to all my resources (look at this to see how to get access to your resources via spring environment).

Spring #Controller and custom MethodNameResolver

I have several controllers in a spring mvc application. They are regular beans that inherit from MultiActionController. They also have a custom MethodNameResolver that inspects a certain request parameter.
Now I am trying to use a new controller - a pojo with #Controller annotation. I am using #RequestMapping to resolve methods.
I am not sure if I understand this correctly, but as explained here in the spring reference, it is possible to use #RequestMapping with various filters (e.g. GET vs POST) without specifying a path, and then if a url applies to several methods then Spring falls back to InternalPathMethodNameResolver to decide which method to invoke.
How can I tell Spring to fall back to my custom MethodNameResolver? Is it enough to inject the resolver to my pojo controller?
(my controller doesn't inherit from any Spring specific class)
I guess you need to declare AnnotationMethodHandlerAdapter bean and set its methodNameResolver property.

Categories

Resources