Must #ComponentScan be placed with #Configuration? (Spring Core) - spring

I read inside many articles that #ComponentScan should be placed with #Configuration on top of a class. Here some references:
we use the #ComponentScan annotation along with #Configuration
annotation to specify the packages that we want to be scanned
(https://www.baeldung.com/spring-component-scanning)
#ComponentScan(basePackages = "com.zetcode") #Configuration public
class Application { ... } (http://zetcode.com/spring/componentscan)
The #ComponentScan annotation is used with the #Configuration
annotation to tell Spring the packages to scan for annotated
components. (https://dzone.com/articles/spring-component-scan)
I was curious to try if without #Configuration an exception would have been thrown. Surprisingly everything works fine even without #Configuration. Here the code:
#ComponentScan
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
I had just one sample bean which got printed.
#Component
public class Car {
}
This was the output of the main method:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
car
Why does it work? and why do they tell to use it with configuration? was it an old requirement?
And even more surprisingly appConfig becomes a bean, even if it does not have any particular annotation such as #Configuration or #Component. So does that mean that anything that gets put as argument of new AnnotationConfigApplicationContext() gets turned into a bean no matter what annotation does it has or has not?
I probably miss some core spring behavior which would justify this. Any idea?

You are still using #Configuration together with #ComponentScan implicitly. By pasing the AppConfig.class as param to the context, it considers it configuration. That would explain the bean created for it as well

Related

Should #ComponentScan stay in the class containing the main method?

I know that #ComponentScan with #Configuration tell Spring where to look for beans.
#ComponentScan
#Configuration
public class MyApp{
...
}
What I do not understand is on which class I have to put these two annotations. Should they stay on the class containing the main method?
Like this
#ComponentScan
#Configuration
public class MyApp{
public static void main(String[] args) {
...
}
}
Or they can stay on whatever class of the application?
The question comes from the fact that Spring has to know the location of #ComponentScan... or is there an automatic way of detection of the #ComponentScan annotation which Spring is performing under the hood?
Hope to have explained myself!
You can put it wherever you want (I usually put mine in com.domain.project-name.config) and just specify the directories it should scan, for example if you want it to scan everything in project use
#ComponentScan("com.domain.project-name")
#Configuration
public class Config {
...
By default, ComponentScan scans all the annotated classes at the current directory level and below.
#Configuration annotation tells the Spring container that the class contains Spring bean configuration.
#ComponentScan annotation tells the Spring container that the annotated class to scan/searches for other annotations and components. You can also define package name to scan with the annotation like #ComponentScan("your.package.name") or you can give package/class names that need not be scanned.
Hence, you can put these annotations on any class that defines your bean configuration and could be required by spring container to parse and create objects for your entities/POJOs, services and DAOs.
To conclude, I would like to add #ComponentScan and other annotations are there for automatic detection. Else, you would need to define XMLs (that's what happens under the hood with annotations) for spring to read and perform these actions.
Using simple example. You can place #ComponentScan with #Configuration in any class which main method can scan.
Main class scans MyScan class which then scan for bean class.
package com.boot.spring;
#SpringBootApplication
#ComponentScan(basePackages = "com.boot.scan")
public class BootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(BootApplication.class, args);
System.out.println(ctx.getBean("demoBean"));
}
}
Bean class is in different package
package com.boot.bean;
#Service
public class DemoBean {
}
Now, bean class is discovered through DemoScan class
package com.boot.scan;
#ComponentScan(basePackages = "com.boot.bean")
#Configuration
public class DemoScan {
}

#EnableAutoConfiguration annotation with class prameter is not initializing properties object

i have following #CongfigurationProperties class
//#Component
#ConfigurationProperties
#PropertySource("classpath:typesofcharge.properties")
public class ChargeProperties {
private HashMap<String,String> charge=new HashMap<>();
public HashMap<String,String> getCharge()
{
return this.charge;
}
}
And this is my Configuration file
#SpringBootApplication
#ComponentScan({"com.vehiclemanagement.config,com.vehiclemanagement.client,"
+ "com.vehiclemanagement.controller,"
+ "com.vehiclemanagement.exception,"
+ "com.vehiclemanagement.model,"
+ "com.vehiclemanagement.service"})
#EnableConfigurationProperties(ChargeProperties.class)
public class VehicleManagementConfig {
public static void main(String[] args) {
SpringApplication.run(VehicleManagementConfig.class, args);
}
}
If i use #Component annotation in ChargeProperties and remove ChargeProperties.class annotation in Configuration class the charge HashMap is initialized properly
If i remove #Component and pass ChargeProperties.class as argument like this
#EnableConfigurationProperties(ChargeProperties.class) like how document says the charge HashMap is empty when i run
I am using spring boot 2.0.2 release .But i am following latest docs. Can anyone explain why this are not working as document suggest
content of property file is as follows
UPDATE the content of property files are as shown
#DO NOT MODIFY THIS FILE
charge.peak=Double_rate;
charge.lateNight=duration_based_charge;
charge.earlyMorning=special_offers;
When specifying ChargeProperies.class on the #EnableConfigurationProperties annotation it will be registered as a bean through the EnableConfigurationPropertiesImportSelector class inside #EnableConfigurationProperties.
So in the example, if you have only annotated the ChargeProperties class with #ConfigurationProperties it will create a chargeProperties bean with an empty charge HashMap because it defaulted back to application.properties as the source.
A custom source can be specified by using #PropertySource.
#PropertySource annotation providing a convenient and declarative mechanism for adding
a PropertySource to Spring's Environment. To be used in conjunction
with #Configuration classes.
As per documentation above, to use #PropertySource to load the custom source, one has to use the #Configuration annotation.
#Configuration
#PropertySource("classpath:typesofcharge.properties")
Under the hood a #Configuration class is a #Component.
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Configuration
So to your question. By specifying a custom #PropertySource without #Configuration, spring did not load the properties in the #PropertySource annotation and defaulted back to the application.properties.
If we use #PropertySource we have to use component otherwise the properties will not be read
since we added the #ComponentScan We don't have to mention #EnableConfiguationProperties annotation at all The propety class object can be autowired as Bean

Spring conditional component scan configuration

I have a configuration class which registers beans based on a very simple condition (checking a property value in application.properties). The configuration class and the condition are the following:
#Configuration
#Conditional(DatabaseConfigurationCondition.class)
#ComponentScan(basePackageClasses = DBConfigComponents.class)
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
}
and
public class DatabaseConfigurationCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("configuration.type").contains("db");
}
}
In addition of the beans registered in this configuration class I have component scan which scans for other components. When the condition is not met, I expect the beans which are defined in the configuration class not to be registered (which happens to be a case), but also I expect other classes which are annotated with #Component (or #Repository, #Service, etc.. ) and are in same folder as DBConfigComponents.class marker interface not to be registered, which does not happen. Beans which are scanned are always registered, no matter if the condition is fulfilled or not.
When I put the #Conditional(DatabaseConfigurationCondition.class) on each #Component annotated class, than it's working correctly, but I don't want to put it on each class separately.
Any suggestion?
Fortunately, I managed to fix this. The problem in my case was that I had another #ComponentScan annotation placed in other configuration class in other Maven module - not conditional on any property. The components which are in same package as DBConfigComponents marker interface were actually scanned by the other configuration class.
The way #ComponentScan works is on package level. Although, in different Maven modules, both configuration classes were in same package. #ComponentScan works perfectly fine with #Conditional. No need #Conditional to be placed on each component separately.
The best way to achieve this is not to annotate these beans using #Component / #Service and #Repository annotations. Instead you should return these as part of the configuration you have setup which would be DatabaseConfigurationLoader. See sample below.
#Configuration
#Conditional(DatabaseConfigurationCondition.class)
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
#Bean
public SomeService someService() {
return new SomeService();
}
#Bean
public SomeComponent someComponent() {
return new SomeComponent();
}
}
Note: Typically #Configuration with #Conditional are used in libraries that you want to include in your spring boot application. Such libraries should not share the same package as your spring boot application. Thus they should not be picked up by #ComponentScan annotation. Beans from libraries should not be annotated with #Component / #Service / #Repository annotations. Spring suggests using AutoConfiguration for that. See https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html & https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html
No need to implement Condition interface, you need to use '#ConditionalOnProperty' annotation:
#Configuration
#ComponentScan(basePackageClasses = DBConfigComponents.class)
#ConditionalOnProperty(name = "configuration.type", havingValue = "db")
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
}
you can use 'prefix' instead of 'havingValue' depending on your needs.

Spring: What happens when we move #ComponentScan to another class in the package?

I have the following classes:
#ComponentScan
public class CDPlayerConfig {
#Autowired
private static CompactDisc cd;
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
CompactDisc cd = context.getBean(CompactDisc.class);
System.out.println(cd);
}
}
public interface CompactDisc {
void play();
}
#Component
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("play song....");
}
}
When I run the class CDPlayerConfig, the program runs successfully. However, if I remove the ComponentScan annotation to CompactDisc interface or SgtPeppers I get the following error:
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'CompactDisc' available
I think that ComponentScan annotation marks the package where Spring looks for beans. CDPlayerConfig, CompactDisc and SgtPeppers are all placed in the same package, so allegedly moving ComponentScan annotation from one class to another should not make a difference.
If so, why do I get an error?
For #ComponentScan to work you have to "tell" spring where to search, or it must find it with help of other, already loaded, #ComponentScan annotated class (your class must be then annotated also with #Component, #Configuration etc. so it could be found).
In your case, you register application context in the first line of main method - you have specified there to load CDPlayerConfig.class which is #ComponentScan annotated so now spring can automatically find other beans in the package:
ApplicationContext context =
new AnnotationConfigApplicationContext(CDPlayerConfig.class);
If you want to move #ComponentScan to another class, you have to change class registered in AnnotationConfigApplicationContext to some #ComponentScan annotated class:
SgtPeppers:
#Component
#ComponentScan
public class SgtPeppers implements CompactDisc {
(...)
Main in CDPlayerConfig:
ApplicationContext context =
new AnnotationConfigApplicationContext(SgtPeppers.class);
Note you should register context from concrete classes (not interfaces).
Also, above sample would work even without #ComponentScan annotation on SgtPeppers, but then beans defined in other classes from the package wouldn't be found.

Spring #Component & #Bean annotation

I believe #Configuration annotation when used in conjunction with #Bean annotation in spring is used to replace xml configuration. However I saw a piece of code where #Bean was used in conjunction with #Component (defined at class level). Is this a valid declaration? Are there any any pros / cons in using #Component with #Bean annotation vs using #Configuration and #Bean.
EDIT:
Thanks #Sundar & #Biju. I did programmatic call between 2 bean methods under Component class. I saw different object values. However when I used Configuration , I saw the same bean values. Based on what you had explained , I assume a regular method call was made when I used #Component , whereas when I used #Configuration , I assume method annotated with #Bean was treated as a Spring Bean
Code
#Component
public class AppConfig {
#Bean(name="customerService")
public CustomerService getCustomerService(){
System.out.println(getService());
System.out.println(getService());
return getService();
}
#Bean
public CustomerService getService(){
return new CustomerServiceImpl();
}
}
Console Output
com.company.service.CustomerServiceImpl#68bbe345
com.company.service.CustomerServiceImpl#30b8a058
Code
#Configuration
public class AppConfig {
#Bean(name="customerService")
public CustomerService getCustomerService(){
System.out.println(getService());
System.out.println(getService());
return getService();
}
#Bean
public CustomerService getService(){
return new CustomerServiceImpl();
}
}
Console Output
com.company.service.CustomerServiceImpl#71623278
com.company.service.CustomerServiceImpl#71623278
It is a valid declaration, however there are catches - the one within a #Component is referred to as a lite-mode and dependencies cannot easily be injected for beans declared in this form. The recommendation is always to use #Bean in a #Configuration annotated class - here is a good reference on this - http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java-basic-concepts
You can use #Component as an alternative for #Configuration. It’s official suggestion from spring team.
Simply declare your #Bean methods on classes not annotated with #Configuration (but typically with another Spring stereotype instead, e.g. #Component). As long as you don’t do programmatic calls between your #Bean methods, this is going to work just as fine, but conditions apply*.
Please refer more info in this link.
http://dimafeng.com/2015/08/29/spring-configuration_vs_component/

Resources