Understanding #Enable... annotations concurrency - java

We have a project that uses spring-boot-cache-starter, registering an ehCache CacheManager implementation, and spreading #Cacheables accross the code.
Then, some other team created an starter, that basically relies on the default configuration autconfigured by spring-boot-cache starter (hashmap) for its own processing of #Cacheable methods.
Both codes contain the #EnableCaching annotation, and our issue is that the behavior is different in case we comment our main project's #EnableCaching annotation.
If we don't comment #EnableCaching in our project, when we use the custom starter, everything works fine. #Cacheables from the
starter are indexed and resolved in the starter scope but
#Cacheables from our domain are resolved in our ehcache.
If we comment #EnableCaching in our project, then both the starter and our project's #Cacheables are tried to be resolved
against our ehCache implementation.
This breaks a lot of preconceptions I had so far:
I always thought an annotation such as #Enable... applied to all the context, regardless of the placement (starter/application configuration), and regardless of whether it was found once or twice when scanning all #Configuration classes.
Why does the case work when both annotations are there, I guess the CacheManager in the spring-boot-cache-starter is a #ConditionalOnBean, so in that case I would expect both projects using the ehcache bean for resolving, not each one's domain
P.S: the #EnableCaching found in our main project is placed on an inner static #Configuration class. Could this be significant?

It is very hard to answer your question if you don't reveal what the custom starter does. In particular, this looks weird to me:
#Cacheables from the starter are indexed and resolved in the starter scope but #Cacheables from our domain are resolved in our ehcache.
Your preconceptions 1 is valid: it doesn't matter where you you put the annotation or if you add it more than once. It will just enable caching for the whole ApplicationContext. In the case of Spring Boot, that will trigger the auto-configuration unless a custom CacheManager bean is defined in user's configuration.
The "each one's domain" sounds broken to me. Are you sure this is what's happening? If you want to store in several cache managers there is not a lot of different ways:
You need to define a CacheResolver and refer to it in the #Cacheable annotations (or #CacheConfig)
You need a special CacheManager that knows where to find the caches in each underlying stores
If each domain has a standard use of #Cacheable it will go against the CacheManager. If you notice the behaviour you are describing, it has nothing to do with #EnableCaching at all.

Related

Is #SpringBootApplication able to find and AutoConfigure all dependency's beans without META-INF/spring.factories?

Why do we need META-INF/spring.factories when create starters for Spring Boot applications? What if omit it at all or leave empty?
Doesn't the target application's #SpringBootApplication which is
a combination of three annotations #Configuration (used for Java-based
configuration), #ComponentScan (used for component scanning), and
#EnableAutoConfiguration
scan everything and find all beans from all the starters with no help of META-INF/spring.factories?
Component Scanning would scan the packages that you give it. You could technically tell it to scan all the packages of your dependencies, too, and it would start loading up any beans defined in them. If you don’t specify any packages to scan, then Spring will use the base package where the annotation is applied, which would very likely not include beans defined in any dependency libs.
There’s another layer to this- a lot of the libraries you use may be using annotations like “#AutoConfigureBefore” to give spring instructions on the order of bean creation. Component Scanning will not respect that, which could result in some weird behaviors if some dependency tries to override a bean from another which is annotated with #ConditionalOnMissingBean (I.e. create this bean only if it doesn’t exist.) You could easily end up with name collision issues where that bean actually gets created first, and then the override bean is created, too.
So the answer seems to be no. You need spring.factories.
Doesn't the target application's #SpringBootApplication scan everything...
No, it doesn't scan everything because if it was it could take a lot of time and resources. Think about it in a way that in order to understand whether the file with an extension *.class contains a bean (something annotated with #Component for example) it needs at least to read a class and analyze the byte code or even load it into memory to check the annotation by reflection.
So if your application's root package is in com.sample.app (the package with the class annotated with #SpringBootApplication), then spring boot by convention scans only the beans in this package and the packages beneath it. This means that it won't scan any thirdparties (assuming they won't be placed in com.sample.app anyway).
Now Its true that you can change the rules of component scanning, but again, you don't want to scan everything for performance reasons at least.
So Autoconfiguration modules (technically implemented with META-INF/spring.factories can specify an additional place (classes annotated with #Configuration) that spring boot will load despite the fact that they are not placed under the packages of your application
or, in other words, they do not obey the default component scanning rules.
In addition, spring.factories file allows to specify much more than auto configuration rules, you can specify environment post processors there for example, and other stuff that can be useful for your application, probably mostly beneficial at the level of application infrastructure, but still.

Internal Implementation of IOC and DI in Spring Boot

Whenever spring boot application runs it sees the #SpringBootApplication annotation and runs the #ComponentScan which scans the classes with the annotations such as #Component etc and makes the object in the container.I have a little bit of idea that it might be using reflections internally to create the objects but I am not able to connect all the dots .I want to know what exact information does #AutoConfiguration gives to the container that it is able to get all the information of all the component annotated clases of any component ?
P.s. I have edited the wrong question
First of all #AutoConfiguration is responsible for setting up the default configurations for a Spring boot application depending on the dependencies we have added in the pom.xml.
The thing you are looking for is #ComponentScan which is what performs the component class scanning within the default package and all of its sub packages. It does this by going through each class in the package and looking for the #Component,#Service or #Repository annotations. If any of them is present then the container adds this as a bean.
#SpringBootApplication internally has the #ComponentScan annotation added to it along with two others.

Why Java Config is favorable in spring boot when compared to XML config?

I am new to spring-boot. I am building a rest based application using spring-boot and was working on setting up security using spring-security. It is my understnading that I can setup spring-security with either xml config or with Java config.
However, I found the following in spring-boot documentation. https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-configuration-classes.html
It is in favor of using Java Config as opposed to XML config. Changes in Java config requires recompilation. Yet, it makes me think why the documentation favors Java Config.
Configuration classes Spring Boot favors Java-based configuration. Although it is possible to call SpringApplication.run() with an XML
source, we generally recommend that your primary source is a
#Configuration class. Usually the class that defines the main method
is also a good candidate as the primary #Configuration.
Many Spring configuration examples have been published on the Internet
that use XML configuration. Always try to use the equivalent
Java-based configuration if possible. Searching for Enable*
annotations can be a good starting point.
15.1 Importing additional configuration classes You don’t need to put all your #Configuration into a single class. The #Import annotation
can be used to import additional configuration classes. Alternatively,
you can use #ComponentScan to automatically pick up all Spring
components, including #Configuration classes.
15.2 Importing XML configuration If you absolutely must use XML based configuration, we recommend that you still start with a #Configuration
class. You can then use an additional #ImportResource annotation to
load XML configuration files.
There are some advantages
Java is type safe. Compiler will report issues if you are configuring right bean class qualifiers.
XML based on configuration can quickly grow big. [Yes we can split and import but still
Search is much simpler, refactoring will be bliss. Finding a bean definition will be far easier.
There are still people who like XML configuration and continue to do it.
For more info you can refer Java configuration advantages Some more reasons

Are Spring-Boot-Test #MockBeans supposed to qualify for #ConditionalOnBean conditions?

I have a java #Configuration class with a FOO #Bean annotated with #ConditionalOnBean(BAR.class). As I expect this bean to be or not provided by the importer project, it's not present anywhere in my project.
In my integration test, I mock Bar.class by means of #MockBeans. But for some reason Spring-Boot -debug tells me it did not found it so my conditional bean has not been loaded.
I'm almost sure this situation has worked properly in the past, but did I configure anything extra? I can't manage to make it work
P.S> I discovered that manually re-registering the #Bean in the same #Configuration as the conditional does not see it neither! Is there any known bug related to his?
Autoreply: The culprit in this case is
You need to be very careful about the order that bean definitions are
added as these conditions are evaluated based on what has been
processed so far. For this reason, we recommend only using
#ConditionalOnBean and #ConditionalOnMissingBean annotations on
auto-configuration classes (since these are guaranteed to load after
any user-defined beans definitions have been added).
P.S2> I realized Bar.class is an interface but I don't see why shouldn't it work as long as an implementation is present
P.S3> I found out that the MockitoTestExecutionListener is executed after the OnBeanCondition class. This seems my problem totally.
This and this explain why it is not possible:
https://github.com/spring-projects/spring-boot/issues/9624 and
https://gitter.im/spring-projects/spring-boot?at=59536ea74bcd78af56538629

Java based dependency injection in Spring

I'm working in a webapp and this is the first time that I'm using Java based configuration. I have a bunch of class to configure all:
ApplicationContext
PersistenceContext
SecurityContext
WebAppInitializer
WebMvcContext
Now I'm defining Spring Data repositories and the service layer so I need to inject the repositories there. Normally I would use Autowired but I've read that it is preferable to define the injections manually so the question is, where?
Maybe neither of the previous configuration classes is suitable for such task but, do I have to create a single class to define all the injections or is better to have on for each function? What happens if the project grows too much?
I think that the main question would be what is best way to organize dependencies in a Spring project. What do you do?
I add here an image of the structure of the project as a petition. I'm trying to decouple layers and now I need to inject UserRepository to UserService.
No, I would not define a single class to do all the injections. All your classes are coupled that way.
I don't understand what "define the injections manually" means. You have to specify them in either XML or annotations. There's no other way that I know of.
You don't say if you're using XML or annotation configuration. I find myself using the latter more of the time, with only enough XML configuration to tell the Spring app context to scan for annotations.
The Spring idiom would have you specify your configuration in layers if you're using XML. It's a moot point for annotations, because they go into your source code.
Your application will read the Spring context on start up, instantiate all the beans, and wire together the necessary dependencies. You're good to go from then on.
I disagree with the link you provided. Avoid autowiring? No.
The article said that he recommends using XML configuration for large projects. This is a very small project at this point. It seems to me that auto wiring with annotations would be fine even by the article's author's words.

Categories

Resources