In the following example is there any different between result and result2 bean definitions:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
#Configuration
public class Application {
#Bean
public Integer data1() {
return 42;
}
#Bean
public Integer data2() {
return 7;
}
#Bean
public Integer result(
#Qualifier("data1") Integer a,
#Qualifier("data2") Integer b) {
return a + b;
}
#Bean
public Integer result2() {
return data1() + data2();
}
public static void main(final String... args) {
final ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
System.out.println(context.getBean("result"));
System.out.println(context.getBean("result2"));
}
}
are there any related best practices?
any drawbacks?
First question: Is there any differences?
Yes, the result version will get two beans it depends on using dependency injection and follow all rules regarding the scopes of these beans. The result2 version calls two factory methods itself and is not taking advantage of dependency injection.
Second and third question: Are there any best practices or drawbacks?
The first version that actually lets spring inject the dependencies benefit from all advantages that comes with spring dependency injection. You can specify scopes and override the specifications of which beans to inject in other contexts.
The other version will just make hardcoded calls to the two factory methods itself, which means that the factory methods themselves cannot have any dependencies injected and will not respect any annotations like scope.
My recommendation is to go with version one which takes follows the dependency injection paradigm. Otherwise, at least the two factory methods should be treated as regular methods and have the spring annotations removed in order not to trick any reader of your code that spring manages the beans lifecycle.
Imagine a non-trivival example where data1 and data2 is creating complex beans that are used by several other beans, and where you may want to change the actual instances based on context, such as unit tests, test/stage environment or production...
Related
I have a Quarkus project where I have most of the business logic placed in services, aka injectable beans using #ApplicationScoped annotations, where all of the CRUD operations take place. In the JAX-RS resource files themselves, the bulk of the logic is just validation, often using whole validation beans. This has meant that we needed to mock our injected services when we tested the resources, to prevent the unit tests from becoming essentially integration tests. We do this having a structure like this (example project);
The file MockGreetingService.java in turn looks like this:
import io.quarkus.test.Mock;
import javax.enterprise.context.ApplicationScoped;
#Mock
#ApplicationScoped
public class MockGreetingService extends GreetingService {
#Override
public String sayHello(String name) {
return String.format("Hello %s, your id is %s", name, "1234");
}
}
Our actual project is a bit more sophisticated than this in the way that the mocks always return our DTO classes regardless of input, but the principle is the same as above. They work flawlessly for our JAX-RS resource tests. However, trying to test the actual service beans themselves means problems with this setup. I built a service test, which uses the same annotations and flow as the code below:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
#QuarkusTest
public class GreetingServiceTest {
#Inject
GreetingService greetingService;
#Test
void checkReturnsHello () {
String result = greetingService.sayHello();
System.out.println(result);
Assertions.assertEquals("hello Martin! Your country is Italy", result);
}
}
With the dependency injection in the class above, which we don't do in our resource tests, I expected Quarkus to understand that we want to use the original service in this test. How foolish of me. A simple log has shown that the mock service methods indeed still run in the latter test above.
Now I wonder - is it a way to disable the mock for this latter test? Preferably without having to modify or remove the mock classes, although I realize that might not be possible in the way I imagine it to be. Thanks in advance!
Sounds like a use case for qualifiers, which enable you to have different implementation beans, and to choose at the injection point which type of bean you prefer:
https://jakarta.ee/specifications/cdi/2.0/cdi-spec-2.0.html#qualifiers
As an alternative, you may also decide to instantiate your service on your own, not using cdi in any way.
In a real project, I found out that #Component may be omitted in the following code:
// no #Component !!!!!
public class MovieRecommender {
private final CustomerPreference customerPreference;
#Autowired
public MovieRecommender(CustomerPreference customerPreference) {
this.customerPreference = customerPreference;
}
// ...
}
#Component
public class CustomerPreference {...}
(The example is taken from the official Spring docs https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation , and the docs show no #Component at all, which may mean either that it is not needed, or that it is just not shown.)
The project where I work does not use any XML bean declarations, but it uses frameworks other than just Spring, so it is possible that something declares the class as a bean. Or it may be a feature of the version of Spring that we use, and if that feature is not documented, it may be dropped later.
Question:
Must the class that uses #Autowired be annotated with #Component (well, be a bean)? Is there any official documentation about that?
UPD Folks, there is no #Configuration and no XML configs in the project, I know that such declarations make a bean from a class, but the question is not about them. I even wrote "(well, be a bean)" in the question above to cover that. Does #Autowired work in a class that is not a bean? Or maybe it declares the class that uses it as a bean?
there are several ways to instantiate a bean in Spring.
One of them indeed is with the #Component annotations, with that, Spring will scan all the packages defined for component-scan and initialize all annotated classes (either with #Component or one of the annotations that uses it - Controller, Service, etc.).
Other way to initialise beans is using a configuration class (annotated with #Configuration) that includes methods annotated with #Bean. each of these methods will create a bean.
There's also an option to create the beans using xml configurations, but this is becoming less and less common, as the annotation-based approach is more convinient
According to https://stackoverflow.com/a/3813725/755804 , with autowireBean() it is possible to autowire a bean from a class not declared as a bean.
#Autowired
private AutowireCapableBeanFactory beanFactory;
public void sayHello(){
System.out.println("Hello World");
Bar bar = new Bar();
beanFactory.autowireBean(bar);
bar.sayHello();
}
and
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
public class Bar {
#Autowired
private Foo foo;
public void sayHello(){
System.out.println("Bar: Hello World! foo="+foo);
}
}
On the other hand, by default the latest Spring does not assume that classes that use #Autowire are #Component-s.
UPD
As to the mentioned real project, the stack trace shows that the constructor is called from createBean(). That is, the framework creates beans from classes declared in the framework's configs.
I wanna switch from xml based spring configuration into java-based. For constructor type injection it is easy. Example I am using:
#Configuration
public class BeanConfiguration {
#Bean
public GreetingService greetingService(GreetingDao greetingDao) {
return new GreetingService(greetingDao);
}
#Bean
public GreetingDao greetingDao() {
return new GreetingDao();
}
}
However, when I want to inject through setter method I am doing something like this:
#Configuration
public class BeanConfiguration {
#Bean
public MeetingDao meetingDao() {
return new MeetingDao();
}
#Bean
public MeetingService meetingService(MeetingDao meetingDao) {
MeetingService meetingService = new MeetingService();
meetingService.setMeetingDao(meetingDao);
return meetingService;
}
}
I am not sure if this is a possible way to inject with Java-based Configuration and setter method. Unfortunately I cannot find any example (for constructor dependencies a lot of examples exists). Also I am not sure in case of Java-based configuration when should I use constructor and when setter. In Spring docs it is described that I should use constructor for required and setter for optional dependency. However, I see it as the same result for this kind of approach.
Thanks for any clarification.
Adam
Under the assumption that you cannot change the classes themselves, you could always just not return the bean until you have injected all the values.
#Configuration
public class YourConfig{
#Value("${some.value.from.properties}")
private String someValue;
#Bean
#Autowired
public YourBean yourBean(TheDependency theDependency){
YourBean bean = new YourBean();
bean.setTheDependency(theDependency);
bean.setSomeValue(someValue);
return bean;
}
}
Constructor injection is always preferred with class dependencies, but not always possible.
If you have access to changing the source for these services and beans you are creating, then I suggest using constructor injection and placing "#Service" on the class and "#Autowired" on the constructors.
Properties are an example of "optional" dependencies; it is common to default values and behavior if not provided. I prefer just placing the "#Value" directly on that field instead of my constructor because otherwise you might end up with WAY too many parameters. This is "setter" injection, but you don't want an actual setter method (again, not normally anyways); you only want Spring to change the value, not any of your other code.
Using "#Value" is fine if you only have one or two properties(or 3? It's not an exact science); however, if you find you have a lot of fields with "#Value" then you should use a configuration bean instead. An "#ConfigurationProperties" bean can also be treated the same way with "setter" injection, but I prefer constructor injection to be sure that at least the bean is never null, even though it's values might be.
in our software we are using spring java config. We have a setup, where one configuration extends an abstract configuration. Please have a look at this testcase:
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class SpringConfigTest {
#Test
public void test() {
final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
ctx.getBeansOfType(AtomicInteger.class).entrySet().stream().forEach(b -> System.out.println(b.getKey() + " : " + b.getValue() + " (" + b.getValue().hashCode() + ")"));
}
#Configuration
public static class MyConfig extends AbstractConfig {
#Bean(name = "anotherName")
public AtomicInteger myBean() {
return new AtomicInteger(5);
}
}
public static abstract class AbstractConfig {
#Bean
public AtomicInteger myBean() {
return new AtomicInteger(10);
}
}
}
The idea is, that MyConfig overwrites AbstractConfig and in the created ApplicationContext there is only one bean of type AtomicInteger under the name anotherName.
The results was:
anotherName : 5 (2109798150)
myBean : 5 (1074389766)
So it says, there are two beans (two instances - one for each name) - and even more surpring: the same method (MyConfig#myBean()) was used to create both of them.
This behaviour looks odd to us: We expected that spring would either respect the usual java way of inheritance and create only the bean from MyConfig... or at least would create two independent beans ("10" and "5") in case it sees AbstractConfig as an independant config.
While investigating this we also tried to register the method name on the MyConfig class:
public static class MyConfig extends AbstractConfig {
#Bean(name = ["anotherName", "myBean"])
public AtomicInteger myBean() {
...
and this time we got only one bean:
anotherName : 5 (2109798150)
.. what was even more surprising for us.
Does anybody know if this is really the correct behaviour or are we only using it wrong? Should we raise a ticket in spring's jira?
Thanks in advance!
I'm not a Spring pro, but I'd say that behaviour is by design. To achieve what you want (I hope I guessed right) "inject this bean instead of the other" you would use #Primary on a bean, to selectively enable a configuration depending on circumstances you would use a #Conditional i.e. #Profile.
In Spring, beans can be wired by type first, but then by name.
Hence #Qualifier("myBeanName") can disambiguate autowiring multiple beans with the same type, e.g.
So:
the very fact that the non-abstract bean has been given another name, causes it to be considered a different bean in the application context.
You can declare beans in a non-configuration class. That is called "lite" mode, but it is still a bean in the application context.
See also this answer on lite mode.
I didn't know one could give a bean more than one name, but since Spring beans are singletons by default, it stands to reason only one bean would be created in the second case, as "myBean" already exists and only one bean with that name can be in the application context.
I'm new to Java and Spring, coming from C# and the .NET world, so bear with me - what I am attempting to do may be off the mark...
I am attempting to configure Spring DI using Java configuration and annotations, not XML configuration, however I am having a few issues. This is for a standalone application, not a web app. I have worked through the springsource documentationand as far as I can tell my very basic configuration should be correct...but isn't. Please take a look at the code below:
Java Configuration Annotated Class:
package birdalerter.common;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import birdalerter.process.ISightingsProcessor;
import birdalerter.process.SightingsProcessor;
#Configuration
#ComponentScan({"birdalerter.process", "birdalerter.common"})
public class AppConfig {
#Bean
#Scope("prototype")
public ISightingsProcessor sightingsProcessor(){
return new SightingsProcessor();
}
}
Configure Component implementing the ISightingsProcessor interface:
package birdalerter.process;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import org.springframework.stereotype.Component;
import birdalerter.domainobjects.IBirdSighting;
#Component
public class SightingsProcessor implements ISightingsProcessor{
private LinkedBlockingQueue<IBirdSighting> queue;
private List<ISightingVisitor> sightingVisitors = new ArrayList<ISightingVisitor>();
public SightingsProcessor(){
}
...
}
Configure Factory Component:
package birdalerter.process;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
public class ProcessorFactory {
private ISightingsProcessor sightingsProcessor;
#Autowired
#Required
private void setSightingsProcessor(ISightingsProcessor sightingsProcessor){
this.sightingsProcessor = sightingsProcessor;
}
public ISightingsProcessor getSightingsProcessor(){
return this.sightingsProcessor;
}
}
Wire up the AnnotationConfigApplicationContext and test:
#Test
public void testProcessingDI(){
#SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();
System.out.println(processor);
Assert.assertTrue(processor != null);
}
The SightingsProcessor is not being setter injected and the assert is failing as the returned object is null. Hopefully I have missed something very obvious.
Thanks in advance.
Edited in Response to Meriton:
Thanks for the answer Meriton.
Why would Spring not know about the newly created object? Does Spring not maintain dependencies throughout the application lifecycle and inject as appropriate when new objects are created that are configured as beans?
I don't want to directly use context.getBean(ISightingsProcessor.class) if I can help it to be honest, I would like the dependency injected in the setter method without having manual intervention - it just seems cleaner.
I am using the ProcessorFactory as the ISightingsProcessor interface extends Runnable - the implementing object is to be started as a thread. The application will be configurable to have n* threads, with each being started within a loop iteration. I don't think it is possible (I may be wrong, please advise if so) to have #Autowired annotations within method declarations, hence I use the factory to supply a new instance of the injected ISightingsProcessor concrete class.
Yes I've just had a look regarding the #Scope annotation - you are right, that needs moving to the AppConfig #Bean declaration (which I've done in this edit), thanks for that.
ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();
This calls the constructor of ProcessorFactory, and then the getter of the instance the constructor created. Spring can not know about that newly created object, and therefore not inject its dependencies. You should ask Spring for the ProcessorFactory instead, for instance with
ProcessorFactory pf = context.getBean(ProcessorFactory.class);
ISightingsProcessor processor = pf.getSightingsProcessor();
That said, I don't know why you need class ProcessorFactory at all. You might just as well get the ISightingsProcessor directly:
ISightingsProcessor processor = context.getBean(ISightingsProcessor.class);
Additionally, "Java Based Configuration" and component scanning are independent ways to declare beans. Currently, you are therefore declaring the ISightingsProcessor twice: Once with the #Bean-annotated factory method, and once with the component scan and the #Component annotation on the class. Doing either of that will do. In fact, doing both might cause one bean definition to override the other.
Oh, and the #Scope annotation is for bean definitions (those you annotate with #Bean or #Component). It will likely be ignored on injection points (#Autowired).