How does bean self-auto-wiring work in Spring? - java

One of the really cool and rather mind boggling features that I have recently discovered in Spring is self auto-wiring a bean.
What I am referring to is this:
class UserServiceImpl implements UserService {
#Autowired
UserService service;
// other service methods...
}
My questions are as follows:
How is this implemented ?
How does Spring manage this ? Does it assign the same object to self auto-wire reference ? Like so:
UserServiceImpl serviceImpl = new UserServiceImpl();
serviceImpl.setService(serviceImpl); // Obviously this would be done via Reflection rather than a setter.
or
does Spring make 2 seperate objects? Like so :
UserServiceImpl obj1 = new UserServiceImpl();
UserServiceImpl obj2 = new UserServiceImpl();
obj1.setService(obj2);
And just gives us obj1 when we request it in a RestController ?
How many copies of the object are there in the Spring Application Context ?
Related to the previous question, how many actual copies of the object are there ?
Its a very convenient feature for things like transactions across methods, but I want to know what is exactly going on behind the scenes here.

It doesn't inject the UserServiceImpl if you use some annotation like #Transactional,#Cachable etc. It actually injects the proxy.
But as the base it uses the same instance.
As of 4.3, #Autowired also considers self references for injection (that is, references back to the bean that is currently injected). Note that self injection is a fallback. Regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary. On the contrary, they always end up as lowest precedence. In practice, you should use self references as a last resort only (for example, for calling other methods on the same instance through the bean’s transactional proxy). Consider factoring out the affected methods to a separate delegate bean in such a scenario. Alternatively, you can use #Resource, which may obtain a proxy back to the current bean by its unique name.

There is only one copy and uses reflection
Lets look at this sample
#Service
public class SampleService {
#Autowired
private SampleService service;
public SampleService getService() {
return service;
}
}
#SpringBootApplication
public class RestServiceApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context
= SpringApplication.run(RestServiceApplication.class, args);
SampleService sampleService = context.getBean(SampleService.class);
//This will print true
System.out.println(sampleService == sampleService.getService());
}
}
As you can see sampleService == sampleService.getService() is true;

Related

SpringBoot - Mock stateful object created via "new" keyword in integration test

I have an SpringBoot application that consists of a Controller layer and a Service layer.
MyController has access to MyService via #Autowired, while MyService has a method that creates a new instance of MyClass, which is imported from an external dependency.
import externaldependency.MyClass;
#Service
public class MyService {
public void myMethod() {
MyClass c = new MyClass();
c.doStuff();
c.doOtherStuff();
c.doMoreStuff();
}
}
I use new to create the instance because MyClass holds state; it has several methods that change its state during the execution of myMethod until I get the desired result, therefore I shouldn't autowire it nor inject it in the constructor, since that would use a single instance of this class for every call to myMethod. I understand that "Prototype" beans exists, but as far as I know, even if I declare MyClass as a prototype bean and inject it to MyService via #Autowired, the service would still use the same instance of MyClass during execution, so ultimately I decided to just use new.
Recently I've been trying to do an integration test, calling my Controller layer, which in turn will call my Service layer, which in turn will create an instance of MyClass. The problem is that one of the many methods of MyClass internally calls an external service, which shouldn't be part of the test itself, so I would like to mock this class.
I understand that mocking is done via dependency injection, but in this case I can't do that. Is there an alternative way to mock MyClass, or is it simply not possible with this setup? If not, then how could I refactor my code to make mocking possible in this particular case?
Many thanks in advance.
I'll answer my own question.
Since MyClass holds state, it shouldn't be autowired to the service nor injected via its constructor, but rather new instances should be created as needed. However, whan can be autowired is a "factory" which creates these instances:
#Component
class MyClassFactory {
public MyClass getInstance() {
return new MyClass();
}
}
Therefore, the service becomes:
#Service
public class MyService {
#Autowired
private MyClassFactory myClassFactory;
public void myMethod() {
// MyClass c = new MyClass();
MyClass c = myClassFactory.getInstance();
c.doStuff();
c.doOtherStuff();
c.doMoreStuff();
}
}
In practice, using a factory is the same thing as just using new; I'm getting a new instance either way. The benefit comes during testing; now I can mock what the factory returns, since the factory is part of Spring's application context:
#SpringBootTest
public class MyTest {
#MockBean
private MyClass myClassMock;
#MockBean
private MyClassFactory myClassFactoryMock;
#Test
public void myTests() {
// Make a mock of MyClass, replacing the return
// values of its methods as needed.
given(
myClassMock.doStuff()
).willReturn(
"Something useful for testing"
);
// Then make a mock of the factory, so that it returns
// the mock of the class instead of a real instance.
given(
myClassFactoryMock.getInstance()
).willReturn(
myClassMock
);
// Do the tests as normal.
}
}
Probably not the most elegant solution, but at least solved my current problem.

Mockito does not recognize class

I tried to user weld-junit5 with mocking a class.
I mock the class because i want to know how often it will be called.
But each time i try to Mockito.verify() this mocked class it throws a "NotAMockException"
The Intellij Debugger is validating the field as: "Mock for MessageService, hashCode: XY"
I already tried to add my testclass into the WeldInitiator but it dont want to work.
"MessageService" is a real class, not an interface (a Interface wouldn't work either)
Docs
#EnableWeld
class GameServiceTest {
#WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
#Produces
#ApplicationScoped
public MessageService createMessageServiceMock() {
return mock(MessageService.class);
}
#Inject
private MessageService messageService;
#Inject
private GameService gameService;
#Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// This will throw a org.mockito.exceptions.misusing.NotAMockException
Mockito.verify(messageService, Mockito.times(1)).writeMessage(any(), any());
}
}
I expect, that the Injected MessageService is a real mock, on which i can call every Mockito function, but it seems not so.
Do I anything wrong, or what is the proper way to do this?
I think I just resolved this problem:
private static final MessageService messageService = mock(MessageService.class);
#Produces
#ApplicationScoped
public MessageService createMessageServiceMock() {
return messageService;
}
To give some background, the way it works is that Weld lets Mockito create the desired object and then takes that as a contextual bean instance.
However, in CDI any bean that has normal scoped needs to have a proxy that is passed around instead of that instance. So what your producer actually does (because it is #ApplicationScoped) is create the object, store that in the context and then also create a proxy and pass around that proxy instead. The proxy is a different object (a delegate with no state) that "knows" how to get reference to the actual instance.
So what happens is that proxy gets injected into the field and you are checking the proxy object with Mockito.verify() call. Obviously, the proxy isn't the mock itself and so it fails. As user #second suggested, Weld offers an API to unwrap the proxy and get the contextual instance. I would argue that the API isn't "ugly", it is just a thing users shouldn't mostly care about but sometimes you cannot avoid it.
You could avoid having proxy by using some of the pseudo scopes which are #Dependent or CDI #Singleton. With that it should work as well and so long as it's for tests, replacing application scoped with singleton should work.
As for your workaround, I do no see how that solves anything - it is basically the same producer and because of the scope it will only be invoked once, hence the static field will make no difference (as there will be a singular call to mock creation). Have you changed something else than that?
As a user of JUnit 5 + Weld-JUnit myself, I am using the following pattern. The reasons are those explained in the answer by Siliarus.
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import ...
#EnableWeld
#ExtendWith(MockitoExtension.class) // (1)
class GameServiceTest {
#WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
#Produces
#ApplicationScoped // (2)
#Mock // (3)
private MessageService messageServiceMock;
// #Inject // (4)
// private MessageService messageService;
#Inject
private GameService gameService;
#Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// (5)
Mockito.verify(messageServiceMock, Mockito.times(1)).writeMessage(any(), any());
}
}
Explanations:
I am using the Mockito extension for convenience
You do not really need to give it application scope
The #Mock annotation is handled by the MockitoExtension. Again, this is only for convenience, you could create the mock yourself in a producer method.
You do NOT need to inject the mock service; you have the messageServiceMock! The injected thing here will be the Weld proxy, as explained by Siliarus.
It is fun to describe this injection a bit more: If the bean is #ApplicationScoped, i.e. "normal-scoped", CDI has to inject a proxy. If you use this proxy instead of the actual mock, you will get the exception. If you follow my advice from (2) and leave out the #ApplicationScoped, the bean will be dependent-scoped and the mock is injected directly. In this case you could use the injected field, but why bother?
Use the mock directly.

DI & Autowiring vs instantiation in Spring [duplicate]

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Placement of #Autowired annotation

I've seen the #Autowired annotation placed just before the constructor of a POJO used as controller.
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
this.usuarioService = usuarioService;
}
// More code
}
This constructor takes as argument the reference to the object we want Spring to inject.However if I place this annotation just before the property declaration the application works just the same.
#Controller
public class LoginController{
#Autowired
private UsuarioService usuarioService;
// More code
}
My question is what is the difference between this two approaches in terms of pros and cons.
My advice to you would be to never use #Autowired on fields (except in Spring #Configuration classes).
The reason is very simple: TESTING!!!!
When you use #Autowired on fields of a class, then that class becomes harder to unit test because you cannot easily use your own (possible mocked) dependencies for the class under test.
When you use constructor injection then is becomes immediately evident what the dependencies of the class are, and creating that class becomes straight forward (simple constructor call).
Some points that need to made:
1) Some might argue that even when #Autowired is used the class can still be unit tested with the use of Mockito's #InjectMocks, or Spring's ReflectionTestUtils.setField, but my opinion is that the creation of a unit under test should be as dead simple as possible.
2) Another point that could be mentioned is that there might be many arguments in the constructor making the manual invocation of the constructor (either in the test or elsewhere) difficult. This however is not a problem regarding the creation of the class, but a problem in the design. When a class has to many dependencies, in most cases it is trying to do too much and needs to broken into smaller classes with fewer dependencies.
#Autowired annotation on setter methods is to get rid of the element in XML configuration file. When Spring finds an #Autowired annotation used with setter methods, it tries to perform byType autowiring on the method
#Autowired annotation on properties is to get rid of the setter methods. When you will pass values of autowired properties using Spring will automatically assign those properties with the passed values or references.
Here is an example of both the usage:
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
This Springsource blog post mentions that constructor injection makes it easy to validate required dependencies, if used in combination with contructors assertions that are good practice anyway and would also work if the class is instantiated outside Spring with the new operator:
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
if (usuarioService == null) {
throw new IllegalArgumentException("usuarioService cannot be null.");
}
this.usuarioService = usuarioService;
}
}
This type of assertions are general best practice that is advised to do independently of the class being a Spring bean or not.
For setter or property injection there is also the #Required annotation for validating missing dependencies or #Autowired(required = true). According to the blog post, constructor injection provides this advantage, but for historical reasons setter injection is more frequently used in Spring.

Autowiring vs instantiating in Spring

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Categories