I have picked up a project that uses #Autowired and dependency injection a lot. People have been saying all the nice things about them. It seems kind of like a magic.
I am new to Spring injection and #Autowired. My first glance of #Autowired is good, but when I work with them on Eclipse, I have difficulties tracing them around when debugging.
For example, is there an easy way in Eclipse that I can see where and how an #Autowired bean is initiated? How do I know if it is initiated correctly the way I want? Is there a way to trace the sequence of it being called/accessed?
Anybody has any tips or comments that may help me to debug #Autowired bean easier on Eclipse?
When a Spring application starts, it first creates instances of beans, either by scanning for annotations, or processing the XML Spring context definition. Some of those beans have to be created in a specific order, like if they use constructor injection. Once beans are created, wiring those beans together can happen.
If you want to see what happens when a bean is constructed, set a breakpoint in the constructors of the class. Look down the stacktrace to see what caused it to be constructed.
Related
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();
}
}
}
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.
As in the title above, I am confused about pros cons between injecting applicationContext by directly #Autowired annnotation or implementing ApplicationContextAware interface in a singleton spring bean.
Which one do you prefer in which cases and why? Thanks.
Actually, both are bad. Both of them tie your application to the Spring framework, thus inverting the whole inversion-of-control concept. In an ideal world, your application should not be aware of being managed by an ApplicationContext at all.
Once you have chosen to violate this principle, it doesn't really matter how you do it. ApplicationContextAware is the legacy version that has been around at least since Version 2.0. #Autowired is a newer mechanism but they work in pretty much the same way. I'd probably go with ApplicationContextAware, because it semantically makes clear what it is about.
As #Sean Patrick Floyd says, the need of ApplicationContext is often due to a bad design. But sometimes you have no other option. In those cases I prefer the use of #Autowired because is the way I inject all other properties. So, if I use #Autowired for injecting MyRepository, why can't I use it for ApplicationContext or any other Spring bean?
I use Spring interfaces only for those things I can't do with annotations, for example BeanNameAware.
If you need to get a prototype in a singleton then you can use method injection. Basically, you create an abstract method that returns the object you need and spring will return the prototype everytime you call that method. You define the "lookup-method" in your spring config. Here are some links:
http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#beans-factory-method-injection
http://java.dzone.com/articles/method-injection-spring
Since you are not extending any of the spring classes your application is always separated from the framework. Most of the cases you will not wanted to inject the ApplicationContext as it, but will need to inject the beans defined in the ApplicationContext.
The best case is always to stick to the bare minimum, until and unless you have any specific requirement and this is very simple with spring.
So either,
Annotate your beans and scan them in application context, then use #Autowire to wire them up.
Use application context to wire your bean expediencies(old xml style configs). You can use #Autowire with this approach also.
When you want to control the bean life cycle, you can read the API and customize it, but most of the time these general settings will do the job.
Here are some examples.
Spring Auto-Wiring Beans with #Autowired annotation
Spring Auto-Wiring Beans XML Style
Spring IoC container API Docs
There is no need to use ApplicationContext at all.
ObjectFactory
If you need to use prototype scoped beans in a singleton bean, inject an org.springframework.beans.factory.ObjectFactory.
For example using constructor injection:
#Service
class MyClass {
private ObjectFactory<MyDependency> myDependencyFactory;
public MyClass(ObjectFactory<MyDependency> prototypeFactory) {
myDependencyFactory = prototypeFactory;
}
}
Why
Now what's the benefit over using ApplicationContext ?
You can substitute this dependency (e.g. in a test) by simply passing a lambda (since ObjectFactory is a #FunctionalInterface) that returns a stubbed version of it.
While it is possible to stub the ApplicationContext, it is not clear in that case which beans will be looked up and need to be stubbed.
I have 20 beans in my application-context,I want to load a particular bean after all the beans are loaded. Is there a way for this?
You can use depends-on to force bean initialization order.
For example if bean1 depends on bean2 and bean3, you can put:
<bean id="bean1" class="YourBean" depends-on="bean2,bean3">
in your spring context.
As #skaffman said, this is a very strange requirement. Depending on your needs there are better solutions:
If you just need to start a process when Spring context is initialized, don't use a #PostConstruct annotated method (or an InitializingBean). ApplicationListener is probably what you need.
If you are worried because you need some beans injected in a #PostConstruct annotated method don't bother: Spring is usually smart enough for resolving such dependencies. If it isn't in your case, maybe you have an overcomplicated bean design.
If this isn't enough, you can follow #soulcheck instructions. This answer can probably help you in order to get cleaner configuration files.
If this don't help you, please give us some more information on what are you trying to achieve.
I'm using spring+scala 2.8. I have a #Transactional bean (marked with #Service), that is enabled in spring via < tx:annotation-driven / >, and when I fire up tomcat the controller that gets #Autowired with this service bean can't find an autowire candidate. I was beating myself up trying to figure out why it couldn't find a candidate object, when the #Service object was clearly getting instantiated (I could see this via log4j debug messages). I eventually decided to simplify by commenting out the < tx:annotation-driven / >, and voila! The webapp starts fine.
Can someone provide a technical reason why this doesn't work? I'm about to try #Qualifier to see if that "fixes" the problem.
When you add <tx:annotation-driven/> to your configuration, it causes various wrapping to happen with proxy classes (see the Spring documentation on transactions). This probably isn't playing well with the #Transactional annotation and Scala.
See Use Spring #Transactional in Scala
So I figured out my issue. It actually may have been "broken" with java as well as scala. My service class consisted only of an implementation class and no interface. Once #Transactional proxied the class spring was unable to find an autowire candidate. Simply adding an interface (or trait in scala) fixed the issue.