Background: I am working in a project named com.x.myproject. I have the dependency of two other packages com.x.document and com.x.library. both packages have the same class with name QueueHelper.
Now, In my project, I have to scan one other package com.x.security which internally scans com.x, something like that:
#SpringBootApplication
#ComponentScan(basePackages = {"com.x"})
#EnableCaching
public class Security {
.......
}
in com.x.myproject
#SpringBootApplication
#ComponentScan(basePackages = {"com.x.myproject","com.x.security"}, excludeFilters={
#ComponentScan.Filter(type=FilterType.REGEX, pattern="com.x.document.*"),
#ComponentScan.Filter(type=FilterType.REGEX, pattern="com.x.library.*")})
public class MyProject{
.......
}
It all works fine when I use excludefilters in com.x.security but I want to use it in com.x.myproject
The exception which I got is
Annotation-specified bean name 'queueHelper' for bean class [com.x.library.utils.QueueHelper] conflicts with existing, non-compatible bean definition of same name and class [com.x.document.utils.QueueHelper]
Three answers come to my mind:
Give a different names to com.x.library.utils.QueueHelper and com.x.document.utils.QueueHelper via the #Component annotation. Spring will use the simple class name by default for naming the beans. You can annotate one with #Component('libraryQueueHelper') and the other with #Component('documentQueueHelper'). However, now you'll have to give a #Qualifier(<name>) in each place you're autowiring these beans.
Exclude them in your module, like you do in your question and then change their names using #Bean annotated methods within a #Configuration. When using in the third module, you'll need to use a #Qualifier to autowire the correct bean.
Rename the classes. This is the best solution in this case, but since you asked this question, I guess it's not viable.
Related
I have the following autoconfigure class.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#Import({LoggerController.class, LogService.class, LogConfig.class})
public class ProviderAutoConfiguration {
}
I need to import all the components, services, configurations using #import annotation, otherwise for example, when I remove LogService.class (LogController autowires LogService) from #Import parameters, it throws the following error
Consider defining a bean of type 'com.log.LogService' in your configuration.
Do I really have to include all of them manuelly as shown above, or is there any other way to automatically detect classes annotated Service, Component or Configuration?
!This is starter library, not a executable app!
The problem with your "library" is that it already needs a lot of moving parts, like Spring Data JPA, properly setup JPA. If that isn't available it will fail, or if you add #EnableJpaRepositories and/or things like #ComponentScan and #EntityScan it will (quite severely) interfere with the (auto)configuration of Spring Boot or the clients. Which is what you want to prevent.
Instead of all those annotations what you need to do is
Conditionally enable #EnableJpaRepositories or just include the dependency and let the auto-configuration kick in (I suggest the latter)
Don't add #ComponentScan, #EntityScan etc. instead use #AutoConfigurationPackage which is designed for starters.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#AutoConfigurationPackage
public class ProviderAutoConfiguration {
}
NOTE: This assumes that the ProviderAutoConfiguration is in the same or a higher package then your other classes. If not specify the basePackages in the #AutoConfigurationPackage.
You can use #ComponentScan to specify the packages you want to scan to find configurations and/or components to load.
Assuming you are using Spring Boot, at least so it seems according to your tags, you should take a look at #SpringBootApplication.
#SpringBootApplication encapsulates #Configuration, #EnableAutoConfiguration, and #ComponentScan annotations with their default attributes. The default value for #ComponentScan means that all the sub packages on the package the #ComponentScan is used are scanned. That is why it is usually a good practice to include the main class in the base package of the project.
If your components, services, configurations are under com.log as direct class or in sub-package, you can use #ComponentScan(basePackages="com.log.*")
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#ComponentScan(basePackages="com.log.*")
public class ProviderAutoConfiguration {
}
i was getting an issue which I couldn't understand, which was:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setApplicant in webService.controller.RequestController required a bean of type 'com.service.applicant.Applicant' that could not be found.
Action:
Consider defining a bean of type 'com.service.applicant.Applicant' in your configuration.
I've done some researches but I still couldn't fixed this problem, when I simply removed the #ComponentScan from my Main Application Class and it worked.
I removed:
//#ComponentScan(basePackageClasses = AdminController.class)
Everything is fine, but i got curious... Can someone please help me?
When you don't use #ComponentScan explicity, #SpringBootApplication annotation on your main class has implementation of #ComponentScan in it(along with #EnableAutoConfiguration). So all the classes marked as #component(or similar annotation like controller, service etc.) get scanned automatically provided they are in the same or sub-package where main class is defined.
Now in your case you added //#ComponentScan(basePackageClasses = AdminController.class) in your main class. What this did that it only created bean for the class AdminController and ignored all other classes.
you should annotate the class Applicant with #Component first.
in your main class annotate the object with #Configuration, EnableAutoConfiguration and #ComponentScan({"com.service.applicant","your.admin.controller.path"}).
in the class RequestController annotate the property of type Applicant with #Autowire.
I have been given a task to assign a property from .properties file to a non Spring bean class using #Value annotation. To do this, I created a method on a #Component annotated class and set the property into it, then called that method from the non Spring bean class. I thought this would work, however, still showing as null.
I was told this is because the #Component annotated class I used is not spring loaded. Question, how can I tell if a class is Spring loaded bean? I have been searching on google but can't find anything helpful aside from examples with #Component or #Configuration annotations. Thanks.
Spring Container is responsible for creating or managing beans. It all satisfy the dependencies by injecting them either through constructor or setter method. But in your case you want the #Value injection in your non spring bean which is really not possible as per my understanding. Because here the spring does not creating the object then how it satisfy the dependencies of it.
You have two options for this situation.
Either annotate class using #Component
Either read property file using Properties
https://www.mkyong.com/java/java-properties-file-examples/
I'm trying to understand the transition from using xml annotation to java based annotation in Spring. I have these definitions
<context:annotation-config>: Scanning and activating annotations for already registered beans in spring config xml.
<context:component-scan>: Bean registration + <context:annotation-config>
is #Configuration and is #ComponentScan.
If lets say I declare all my beans with #Component (disregard first the more specific ones like #Repository, #Service etc) annotation and make sure that the packages are getting scanned by the #ComponentScan annotation, what is a particular use case where I will still annotate my class with both #Configuration together with #ComponentScan?
I ask this question because sometimes I see classes annotated with both #Configuration and #ComponentScan at the same time.
First read the following carefully:
Difference between <context:annotation-config> vs <context:component-scan>
Thus <context:component-scan> does the scan job and the same job than <context:annotation-config> does, it means work around with the DI annotations
Then now consider:
<context:component-scan> equivalent to #ComponentScan
<context:annotation-config> no equivalent for annotation.
what is a particular use case where I will still annotate my class
with both #Configuration together with #ComponentScan?
#Configuration is used to define beans about Infastructure such as Database, JMS etc...
Yes, a class can use both, It could be used for example for MVC Infrastructure #Configuration such as:
#EnableWebMvc
#Configuration
#ComponentScan("com.manuel.jordan.controller", "com.manuel.jordan.rest")
public class WebMvcConfig extends WebMvcConfigurerAdapter {
Thus from that class your are configuring MVC and indicating only to scan the MVC classes created by you for the "web side", such as: #Controller, #RestController.
This really depends on your likings and coding style. Documentation states:
Either basePackageClasses() or basePackages() (or its alias value()) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
So every time you see just #ComponentScan annotation this means that all sub-packages should be scanned. This is a reasonable approach to take with package per feature layout: when you have a #Configuration class for your feature and all #Components related to the feature in sub-packages.
Right now i have a inherited project that is using annotation based spring dependency injection. So all classes are simply marked with #Component (or specific stereoTypes like #service, #Repository,#RestController, etc). This makes it a little hard to find where the dependency is located and i was thinking to change it so that each package has its own dependency configuration and then add each package to the #ComponentScan afterwards.
So for example if i had a package called com.mycoolpackage.login and mycoolpackage.networking
then i'd have a Spring configuration like this in first package:
#Configuration
public class LoginDIConfig {
#Bean
public LoginServiceImpl loginServiceImpl() {
return new LoginServiceImpl();
}
}
and in the second package i'd have the following:
#Configuration
public class NetworkDIConfig {
#Bean
public NetworkServiceImpl networkServiceImpl() {
return new NetworkServiceImpl();
}
}
and my#ComponentScan would look like this:
#ComponentScan(basePackages = {"com.mycoolpackage.login","com.mycoolpackage.network"})
So i have two questions about this approach.
How can i use a #Service annotation instead of bean here
Do you think this design is more easier as it tells you what your package dependencies are very easily instead of hunting them
down.
If you want to configure some been properties manually then you should go for above configuration else you should stick with exiting one.
This makes it a little hard to find where the dependency is located
#Autowire Or #Inject annotation will always lead you to dependency class.