spring IoC: where to put ComponentScan - spring

Here my spring configurer:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
#Slf4j
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
log.info("Web security performing");
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.cors().and()
.csrf().disable()
.authorizeRequests().anyRequest().permitAll();
log.info("Web security performed");
}
}
Nevertheless, it's never reached.
Here my application class:
#ComponentScan({
"cat.gencat.catsalut.hes.core.domain.mpi",
"cat.gencat.catsalut.hes.core.repository"
})
#SpringBootApplication(exclude = JmxAutoConfiguration.class)
public class ProjectApplication {
As you can see, #ComponentScan is placed on main ProjectApplication class.
I've realized that when I remove #ComponentScan from my main ProjectApplication class, my WebSecurityConfiguration is detected.
When it's present, WebSecurityConfiguration is ignored.
Any ideas?

SpringBootApplication without specifying #ComponentScan by default scan all classes in the current and those that are located in subpackages for picking Beans and Configuration and other stuffs. if you specify
#ComponentScan({
"cat.gencat.catsalut.hes.core.domain.mpi",
"cat.gencat.catsalut.hes.core.repository"
})
then only cat.gencat.catsalut.hes.core.domain.mpi and cat.gencat.catsalut.hes.core.repository and their subpackages will be scanned for beans. so try to put the class which contains #SpringBootApplication in the root of your project or use #SpringBootApplication(scanBasePackages = {'package1', 'package2'}) to specify packages that have to be scanned.

Try to rely on spring boot default conventions first:
Assuming you've placed ProjectApplication in the com.mycompany.myapp package
You can:
Remove the #ComponentScan annotation from it
Place WebSecurityConfiguration class in the same package com.mycompany.myapp or any package beneath it: Example: com.mycompany.myapp.web.security.config.
When spring boot application starts by default it has a very well defined policies of what should be scanned, so it scans the package of the application itself (the package where the file annotated with #SpringBootApplication resides) and the packages beneath it.
You can alter this behavior with #ComponentScan , but then you might have issues in spring boot driven tests. So without a reason I don't think you should really go there. Of course, if you have an actual reason of altering the default component scanning policies, please share so that our colleagues/me could try to come up with a solution.

Related

what is the difference between using #EnableWebMvc + WebMvcConfigurer and WebMvcConfigurer?

what is the difference between using #EnableWebMvc + WebMvcConfigurer and WebMvcConfigurer??
#Configuration
#EnableWebMvc
class WebMvcConfig(): WebMvcConfigurer {}
#Configuration
class WebMvcConfig(): WebMvcConfigurer {}
#Configuration
class WebMvcConfig(): WebMvcConfigurer {}
This will only take effect if #EnableWebMvc is used. The WebMvcConfigurer instancs are detected by an instance of DelegatingWebMvcConfiguration which is registered through #EnableWebMvc. So for this to work you need #EnableWebMvc.
NOTE: When using Spring Boot, this is automatically done when Spring Boot detects Spring MVC classes on the classpath!.
Without #EnableWebMvc a WebMvcConfigurer doesn't do anything but take up memory. When not using #EnableWebMvc the DispatcherServlet will install some defaults. Those defaults are hardcoded in the DispatcherServlet.properties file. Those defaults are hard to modify without the use of #EnableWebMvc.
WARNING: When using Spring Boot andadding #EnableWebMvc, will actually disable a large part of the MVC auto-configuration done by Spring Boot, which can lead to other surprises!

Does #SpringBootApplication scans test folder for configurations?

I've a #SpringBootApplication annotation in main class of my Spring Boot Application with ordinary folders structure (and #SpringBootApplication is one level package upper then beans in other packages)
I defined some #Configuration classes in some packages but under the test folder.
Will #SpringBootApplication autoconfigure it when start application?
Will #SpringBootApplication autoconfigure it when it will be finded by #SpringBootTest (it's also one level upper but in test folder) when test started?
I am not completely sure, but I would say no, #SpringBootApplication does not scan #Configuration classes in your test folder. What you should use instead is #TestConfiguration and then in your #SpringBootTest add #Import(YourTestConfiguration.class). Find an example below:
#TestConfiguration
public class YourTestConfiguration {
#Bean
(...)
}
#SpringBootTest
#Import(YourTestConfiguration.class)
class AppTests {
(...)
}
You can read more about this and check complete examples in the following online resources:
https://reflectoring.io/spring-boot-testconfiguration/
https://howtodoinjava.com/spring-boot2/testing/springboot-test-configuration/

How to set different prefix for endpoints and for static content in spring boot?

I would like to ask if it is possible (and how) to set different prefixes for static content and for endpoints in the spring boot app. I have been using server.servlet.contextPath=/api in application properties but it also sets the prefix for static content.
What I would like to achieve is to have "/api" prefix for endpoints in controllers and to serve the static content from "/" root.
EDITED
Actually what I need is to be able to set only the static content to "/" and rest of the app be available on "/api"
Spring Boot uses the built-in WebMvcAutoConfigurationAdapter for a Webapplication. The default behavior is defined within this class.
I assume your controllers are annotated with #RestController. If this is the case, you're able to map all controllers to a different location.
Create a configuration class which implements the WebMvcConfigurer interface. Override the method configurePathMatch(PathMatchConfigurer configurer) and implement your desired path configuration.
In the following example, the static content will still be served at "/" and all REST endpoints will be accessible with "/api" as prefix.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerTypePredicate;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
You'll notice there's no #EnableWebMvc annotation in this class, because it would disable the Spring Boot autoconfiguration mechanism for WebMvc.

Spring boot actuator not showing when I use #ComponentScan

My application looks like below. In this configuration my application works (it is bootstrapped with the #ComponentScan).
Unfortunately then /actuator/health does not work. When I remove #ComponentScan then actuator works but my application does not work.
What do I need to configure to make both #ComponentScan and actuator work?
#EnableAutoConfiguration
#SpringBootApplication
#ComponentScan(basePackageClasses = {DistributionApp.class})
public class Main extends SpringBootServletInitializer {
...
}
I found the actual issue.
I had a class with:
#Component
#ApplicationPath("/")
This shadowed the /actuator endpoints. So they did not show up.
So the problem was not related to #ComponentScan but it only surfaced when my own classes were activated.

How is #ConfigurationProperties-annotated classes detected automatically with #SpringBootApplication Annotation

I am learning Spring Boot and have a question with one example in the reference documentation.
Following section of the documentation mentions
6. Using the #SpringBootApplication Annotation
A single #SpringBootApplication annotation can be used to enable those
three features, that is:
#EnableAutoConfiguration: enable Spring Boot’s auto-configuration
mechanism
#ComponentScan: enable #Component scan on the package where the
application is located (see the best practices)
#Configuration: allow to register extra beans in the context or import
additional configuration classes
and the following example to replace this single annotation by any of the features that it enables is bit confusing for me . The example
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
#Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Explanation for the example
In this example, Application is just like any other Spring Boot
application except that #Component-annotated classes and
#ConfigurationProperties-annotated classes are not detected
automatically and the user-defined beans are imported explicitly (see
#Import).
The only major difference I see in the example code above is that it does not have #ComponentScan annotation. I also read in the comments section of an SO answer (Stephane Nicoll May 5 '17 at 11:07) that #Component annotation is not recommended officially to auto detect #ConfigurationProperties. So my assumption is that Spring framework classes with #ConfigurationProperties are not annotated with #Component.
Also I checked the #SpringBootApplication annotation source and couldn't identify anything that should enable the automatic detection of #ConfigurationProperties annotated classes.
The reference document 2.8.3. Enabling #ConfigurationProperties-annotated types section shows the following way to scan and autodetect #ConfigurationProperties
#SpringBootApplication
#ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
With all these details , I would like to understand
Why is it explicitly mentioned for this example that #ConfigurationProperties-annotated classes are not detected automatically ? and How is #ConfigurationProperties annotated classes automatically detected when #SpringBootApplication is used.
Additional note : I saw a small difference between the prior version of the documentation and the current one. The following reference is missing the current one
Keep in mind that the #EnableConfigurationProperties annotation is
also automatically applied to your project so that any existing bean
annotated with #ConfigurationProperties is configured from the
Environment
Following is what I understand from my analysis.
#ConfigurationProperties annotated types can be registered to the ApplicationContext by
Annotating the class with #ConfigurationProperties with an
annotation that falls in the scope of #ComponentScan (
#Component, #Service and the like ) . Not recommended as per the comment from Stephane Nicoll , which makes sense to me now.
Using annotation
#EnableConfigurationProperties . For this to
work the class annotated with #EnableConfigurationProperties
should be annotated with an annotation that falls in the scope of
#ComponentScan ( #Component, #Service and the like )
Using annotation #ConfigurationPropertiesScan and by making sure
the classes annotated with #ConfigurationProperties is placed
under its radar. The usage is similar to #ComponentScan .
Now , when we replace #SpringBootApplication with individual annotations that it enables and omit #ComponentScan (as in example) , the #EnableConfigurationProperties way (Point 2) of registering the types with #ConfigurationProperties will not work. This probably answers both my questions on why and how .
This was explicitly mentioned probably because the connection between #EnableConfigurationProperties and #ComponentScan is not that obvious for people like me.
Additional details.
The registration of #ConfigurationProperties annotated types when we use #EnableConfigurationProperties happens through of the EnableConfigurationPropertiesRegistrar class that is imported by the annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Import(EnableConfigurationPropertiesRegistrar.class)
public #interface EnableConfigurationProperties {..}

Resources