Does ComponentScan order matter? - spring

I'm setting up a very small Spring/REST/JPA project with Boot, using annotations.
I'm getting some Bean not found errors in my REST controller class that has an Autowired repository variable, when I move my JPA repository class out to a different package, and calling componentscan on its package. However, everything was working fine when all my files(5 total) were in the same package.
So I was wondering, however unlikely, if the component scan order matters? For example, if a class is AutoWiring some beans from a package that has not been 'component scanned' yet, will that cause a Bean not found error?

No, Spring loads all configuration information, from files and annotations and the environment when appropriate. It then creates beans (instances of classes) according to a dependency tree that it calculates in memory. In order to do this it has to have a good idea of the entire configuration at startup. The whole model derived from all the aggregated configuration information is called the Application Context.
In modern versions of spring the application context is flexible at runtime and so it's not quite the case that all the configuration is necessarily known up front, but the configuration that is flexible is limited in scope and must be planned for carefully.

Maybe you need to share some code. When you move that stuff, you also need to tell Spring where they went. My guess would be you haven't defined #EntityScan and #EnableJpaRepositories (which default to the location of #EnableAutoConfiguration).

There could be several problems:
You moved your class out of the some package where you have #ComponentScan without arguments. That basically means that components are scan only in this package and its children. Thus, moved class are not scanned and there is no bean to wire.
Wrong package name in #ComponentScan args.
The order isn't matter at all. There is an #Order annotation, but it's purpose is more about loading multiple implementations of sth in a different order.
At first Bean Definitions are created and they have nothing to do with wiring. Then via bean post processors, autowired beans are injected. Since there were no bean definition. There is nothing to inject.

In a well structured program it doesn't, because first each bean gets instantiated, then autowired and then you can actually use them.
However there could be situations where the order does matter and I had an issue figuring out what was going on. So this is an example where it would matter:
You have some Repository that you want to fill with data initially, call it SetupData component.
Then you use #PostConstruct to save the default objects.
You have some component that this Repository depends on but isn't managed by Spring, for example a #Converter.
And that #Converter depends on some other component which you would statically inject.
In this case #PostConstruct methods will be executed before the components into your #Converter get autowired which will result in an exception.
Relying on ComponentScan order is a bad habit, because it's not intuitive especially when you are working with multiple people who may not know about. Or there might be such dependencies that you can't fix the code by changing the scan order.
The best solution in this case was using a task executor service that takes care of running initialization functions.

Related

How to understand the annotation #ComponentScan work when wiring Bean without application.xml?

1, When my dictionary tree likes these, the error "#EnableAsync annotation metadata was not injected" occurs。
2, But when my dictionary tree likes this, the error doesn't happen.
3, When I wire Bean with application.xml, and the dictionary tree likes paragraph one, but the error also doesn't happen.
So what I am so confirmed is that #ComponentScan's work when wiring Bean without application.xml?
When a class does not include a package declaration, it is considered to be in the “default package” (src.main.java). The use of
the “default package” is generally discouraged and should be avoided.
It can cause particular problems for Spring Boot applications that use
the #ComponentScan, #ConfigurationPropertiesScan, #EntityScan, or
#SpringBootApplication annotations, since every class from every jar
is read.
Spring Boot favors Java-based configuration. Although it is possible
to use SpringApplication with XML sources, we generally recommend that
your primary source be a single #Configuration class. Usually the
class that defines the main method is a good candidate as the primary
#Configuration.
This is a classic bug when first making a spring application, it is better to have all your classes in a package, never put your classes in the "default" (src.main.java) package.
Read more here from chapter "2. Structuring Your Code" to "3. Configuration Classes":
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-configuration-classes

Spring Context Test With Just One Bean

What's the recommended way to run a spring boot test where only the one subject under test is configured in the context.
If I annotate the test with
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.profiles.active=test")
#ContextConfiguration(classes = MyTestBean.class)
Then it seems to work - the test passes, the context starts quickly and seems to only contain the bean that I want. However, this seems like an incorrect use of the #ContextConfiguration(classes = MyTestBean.class) annotation. If I understand correctly the class that I reference is supposed to be a Configuration class, not a regular spring service bean or component for example.
Is that right? Or is this indeed a valid way to achieve this goal? I know there are more complex examples like org.springframework.boot.test.autoconfigure.json.JsonTest which use #TypeExcludeFilters(JsonExcludeFilter.class) to control the context - but this seems overkill for my use case. I just want a context with my one bean.
Clarification
I know that I can just construct the one bean I am testing as a POJO without a spring context test and remove the three annotations above. But in my precise use case I am actually reliant on some of the configuration applied to the context by settings in the application-test.properties file - which is why I've made this a Spring Boot test with a profile set. From my perspective this isn't a plain unit test of a single class in isolation of the spring context configuration - the test is reliant on certain configuration being applied (which is currently provided by the spring boot app properties). I can indeed just test the components as a POJO by creating a new instance outside of a spring context, I'm using constructor injection making the providing of necessary dependencies simple but the test does rely on things like the log level (the test actually makes assertions on certain logs being produced) which requires that the log level is set correctly (which is currently being done via logging.level.com.example=DEBUG in a properties file which sets up the spring context).
For starters, reading the documentation first (e.g., the JavaDoc linked below in this answer) is a recommend best practice since it already answers your question.
If I understand correctly the class that I reference is supposed to be
a Configuration class, not a regular spring service bean or
component for example.
Is that right?
No, that's not completely correct.
Classes provided to #ContextConfiguration are typically #Configuration classes, but that is not required.
Here is an excerpt from the JavaDoc for #ContextConfiguration:
Annotated Classes
The term annotated class can refer to any of the following.
A class annotated with #Configuration
A component (i.e., a class annotated with #Component, #Service, #Repository, etc.)
A JSR-330 compliant class that is annotated with javax.inject annotations
Any other class that contains #Bean-methods
Thus you can pass any "annotated class" to #ContextConfiguration.
Or is this indeed a valid way to achieve this goal?
It is in fact a valid way to achieve that goal; however, it is also a bit unusual to load an ApplicationContext that contains a single user bean.
Regards,
Sam (author of the Spring TestContext Framework)
It is definitely a reasonable and normal thing to only test a single class in a unit test.
There is no problem including just one single bean in your test context. Really, a #Configuration is (typically) just a collection of beans. You could hypothetically create a #Configuration class just with MyTestBean, but that would really be unnecessary, as you can accomplish doing the same thing listing your contextual beans with #ContextConfiguration#classes.
However, I do want to point out that for only testing a single bean in a true unit test, best practice ideally leans towards setting up the bean via the constructor and testing the class that way. This is a key reason why the Spring guys recommend using constructor vs. property injection. See the section entitled Constructor-based or setter-based DI of this article, Oliver Gierke's comment (i.e. head of Spring Data project), and google for more information. This is probably the reason you're getting a weird feeling about setting up the context for the one bean!
You can also use ApplicationContextRunner to create your context using a test configuration of your choice (even with one bean if you like, but as other people have already mentioned for one bean it's more reasonable to use the constructor the classical way without using any spring magic).
What I like this way of testing is the fact that test run very fast since you don't load all the context. This method is best used when the tested bean doesn't have any Autowired dependencies otherwise it's more convenient to use #SpringBootTest.
Below is an example that illustrates the way you can use it to achieve your goal:
class MyTest {
#Test
void test_configuration_should_contains_my_bean() {
new ApplicationContextRunner()
.withUserConfiguration(TestConfiguration.class)
.run(context -> {
assertThat(context.getBean(MyTestBean.class)).isNotNull();
});
}
#Configuraiton
public static class TestConfiguration {
#Bean
public MyTestBean myTestBean(){
new MyTestBean();
}
}
}

Spring: Nature of #Import in #Configuration

How does importing one #Configuration to another actually works in Spring? I have figured out, typically only one context is created even when there are multiple #Configuration files involved. Different configurations just balances the bean definitions to logical units, right? In the end, everything are imported to Root context. But the question is, in which order the import is actually done. I can imagine to scenarios.
Individual #Configuration creates their own private context, which is initialized before/parallel with the root context, and in the end is merged with the Root context using #Import. Thus, those configurations doesn't have access to Root context out of box, and may cause ambiguity when performing autowiring and AOP proxying on business objects across different configurations.
or
When importing #Configuration, the parent (Root context) is initialized first, and provides the context for additional configurations to perform their logic against. Thus, parent can do all the component scanning and imported configurations will have those beans available at any time. This means more centralized design and smaller risk for dependency issues.
I'm curious which way Spring does it, because I'm getting strange circular dependency issues when working with method level security on Spring, which uses AOP proxies. I pushed isolated sample of the problem in github, if somebody minds to enlighten me.
https://github.com/nostalgiatune/SpringCircularDependency

Spring Instantiation and 'unused beans'

I'm working on a project which means customising an existing application (JasperServer 3.7.1) which is implemented in Spring 2.5.6 (plus a host of other Spring frameworks).
The application consists of a host of applicationContext*.xml containing the bean definitions which when wired together by Spring bring the app to life - I think it's a typical Spring app configuration as although it my first experience using Spring, it seems all quite well put together and follows a lot of the examples I have seen on the web and in books..
Because I'm actually modifying an existing application, changing beans like filterChainProxy (because we have our own security model ,for example) I'm wary of changing the actual config files that come with the product - instead, where possible, I'd prefer to add extra appContext config files to the existing ones which override existing beans (ie leave the original config in tact, as much as possible).
This I've managed to do by creating beans implementing BeanFactoryPostProcessor which on pre-bean initialisation allow me to change the existing property values/bean references to custom ones. This all seems to be working fine.
My query is, say I had a bean with a property that referred to another bean, and my overrider bean changed that reference to my own version of bean, will Spring still instantiate the bean that is no longer referred to ? The reason for asking obviously is that some of these unused beans may be taking up resources, which may be an unwanted overhead.
Thanks in advance
I'm not sure I follow your example, but it might help to clarify a few things.
Generally, Spring will instantiate a bean for every non-abstract bean definition in the context (this is ignoring things like non-singleton bean scopes, but I'll ignore that for the purposes of this explanation). If multiple bean definition files are used, and some bean names are duplicated, then some definitions will be overridden by others. so far, so good, this seems to be what you wanted.
Once the bean definitions have been established, and any duplicated dealt with, then Spring will then instantiate a bean for each of those definitions. If you have changed the definition of BeanA so that it no longer refers to BeanB, but instead refers to BeanC, but the definition of BeanB still exists, then BeanB will still be instantiated, even if it's not being used.
If that example is not representative of your question, then please elaborate.

Managing complexity in a dependency-injected app with a large number of beans

I'm working on an Spring application which has a large number of beans - in the hundreds - and it's getting quite cumbersome to use and document.
I'm interested in any experience you have with DI-enabled apps with a large number of beans which would aid maintainability, documentation and general usage.
Although the application is Spring-based with a couple of context files, I'm open to listening about suggestions regarding any DI container and about DI in general as well.
You can use component scan and autowiring features to dramatically decrease the amount of Spring XML configuration.
Example:
<beans>
<!-- Scans service package looking for #Service annotated beans -->
<context:component-scan base-package="my.root.package.service"/>
</beans>
Your service classes must be annotated in order to be automatically scanned:
package my.root.package.service;
#Service("fooService")
public class FooServiceImpl implements FooService{
}
You can also use the #Autowired annotation to tell Spring how to inject the bean dependencies:
package my.root.package.service;
#Service("barService")
public class BarServiceImpl implements BarService{
//Foo service injected by Spring
#Autowired
private FooService fooService;
//...
}
I found the following to be of use:
split your Spring configurations into multiple standalone configurations, and use Spring's import facility to import configuration dependencies (see here, section 3.2.2.1). That way you have a set of configurations that you can combine or disassemble as required, and they are all self-dependent (all the dependencies will be explicit and referenced)
Use an IDE that is Spring-aware, and allows you to navigate through the configurations via point-n-click on beans (references/names, to-and-from source code). Intellij works very well at this (version 7 and beyond, I think). I suspect Eclipse would do something similar.
Revise what you're injecting where. You may want to refactor multiple bean injections into one composite or 'meta' bean, or a larger component. Or you may find that components you once thought you'd need to inject have never changed, or never demanded that injectability (for testing, implementing as strategies etc.)
I used to work with a huge Spring installation, with hundreds (thousands?) of beans. Splitting the configurations up made life a lot more manageable, and simplified testing/creating standalone processes etc. But I think the Intellij Spring integration that came with Intellij made the most difference. Having a Spring-aware IDE is a major timesaver.
As #Wilson Freitas says, use autowiring. I daily work with a system that has few thousand spring managed beans using mostly autowired. But I think the notion of "retaining the overall picture" is slightly misplaced. As a system grows you can't expect to do that in the same way as you did on a smaller system. Using #Autowiring forces you to use stronger typing than xml-based spring, which again means you can use the dependency tracking features of your IDE to navigate in dependencies.
I really think it's suboptimal to think that you need to understand too much of the "full" picture when it comes to the spring configuration. You should be focusing on your code and it's dependencies. Managebility and maintainability are achieved by organizing this code well, naming things well and managing your coupling; all of the stuff that applies even if you're not using spring. Spring shouldn't change much, and with the approval of JSR-330, it may even seem like dependency injection will creep further "under the hood" of the runtime environment.
Our strategy is:
naming conventions, e.g.: fooService, fooDao, fooController;
property setters following these conventions;
autowiring by name (autowire="byName"); we had many problems with autowiring by type, especially on the controller layer

Resources