I'm a little confused as to how the inversion of control (IoC) works in Spring.
Say I have a service class called UserServiceImpl that implements UserService interface.
How would this be #Autowired?
And in my Controllers, how would I instantiate an instance of this service?
Would I just do the following?
UserService userService = new UserServiceImpl();
First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".
Second, each application has an entry point to that context. Web applications have a Servlet, JSF uses a el-resolver, etc. Also, there is a place where the application context is bootstrapped and all beans - autowired. In web applications this can be a startup listener.
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
What is "living" in the application context? This means that the context instantiates the objects, not you. I.e. - you never make new UserServiceImpl() - the container finds each injection point and sets an instance there.
In your controllers, you just have the following:
#Controller // Defines that this class is a spring bean
#RequestMapping("/users")
public class SomeController {
// Tells the application context to inject an instance of UserService here
#Autowired
private UserService userService;
#RequestMapping("/login")
public void login(#RequestParam("username") String username,
#RequestParam("password") String password) {
// The UserServiceImpl is already injected and you can use it
userService.login(username, password);
}
}
A few notes:
In your applicationContext.xml you should enable the <context:component-scan> so that classes are scanned for the #Controller, #Service, etc. annotations.
The entry point for a Spring-MVC application is the DispatcherServlet, but it is hidden from you, and hence the direct interaction and bootstrapping of the application context happens behind the scene.
UserServiceImpl should also be defined as bean - either using <bean id=".." class=".."> or using the #Service annotation. Since it will be the only implementor of UserService, it will be injected.
Apart from the #Autowired annotation, Spring can use XML-configurable autowiring. In that case all fields that have a name or type that matches with an existing bean automatically get a bean injected. In fact, that was the initial idea of autowiring - to have fields injected with dependencies without any configuration. Other annotations like #Inject, #Resource can also be used.
Depends on whether you want the annotations route or the bean XML definition route.
Say you had the beans defined in your applicationContext.xml:
<beans ...>
<bean id="userService" class="com.foo.UserServiceImpl"/>
<bean id="fooController" class="com.foo.FooController"/>
</beans>
The autowiring happens when the application starts up. So, in fooController, which for arguments sake wants to use the UserServiceImpl class, you'd annotate it as follows:
public class FooController {
// You could also annotate the setUserService method instead of this
#Autowired
private UserService userService;
// rest of class goes here
}
When it sees #Autowired, Spring will look for a class that matches the property in the applicationContext, and inject it automatically. If you have more than one UserService bean, then you'll have to qualify which one it should use.
If you do the following:
UserService service = new UserServiceImpl();
It will not pick up the #Autowired unless you set it yourself.
#Autowired is an annotation introduced in Spring 2.5, and it's used only for injection.
For example:
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
#Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
A a;
// With setter and getter method
public void showDetail() {
System.out.println("Value of id form A class" + a.getId(););
}
}
How does #Autowired work internally?
Example:
class EnglishGreeting {
private Greeting greeting;
//setter and getter
}
class Greeting {
private String message;
//setter and getter
}
.xml file it will look alike if not using #Autowired:
<bean id="englishGreeting" class="com.bean.EnglishGreeting">
<property name="greeting" ref="greeting"/>
</bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
If you are using #Autowired then:
class EnglishGreeting {
#Autowired //so automatically based on the name it will identify the bean and inject.
private Greeting greeting;
//setter and getter
}
.xml file it will look alike if not using #Autowired:
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
If still have some doubt then go through below live demo
How does #Autowired work internally ?
You just need to annotate your service class UserServiceImpl with annotation:
#Service("userService")
Spring container will take care of the life cycle of this class as it register as service.
Then in your controller you can auto wire (instantiate) it and use its functionality:
#Autowired
UserService userService;
Spring dependency inject help you to remove coupling from your classes.
Instead of creating object like this:
UserService userService = new UserServiceImpl();
You will be using this after introducing DI:
#Autowired
private UserService userService;
For achieving this you need to create a bean of your service in your ServiceConfiguration file. After that you need to import that ServiceConfiguration class to your WebApplicationConfiguration class so that you can autowire that bean into your Controller like this:
public class AccController {
#Autowired
private UserService userService;
}
You can find a java configuration based POC here
example.
There are 3 ways you can create an instance using #Autowired.
1. #Autowired on Properties
The annotation can be used directly on properties, therefore eliminating the need for getters and setters:
#Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
#Component
public class UserController {
#Autowired
UserService userService
}
In the above example, Spring looks for and injects userService when UserController is created.
2. #Autowired on Setters
The #Autowired annotation can be used on setter methods. In the below example, when the annotation is used on the setter method, the setter method is called with the instance of userService when UserController is created:
public class UserController {
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
3. #Autowired on Constructors
The #Autowired annotation can also be used on constructors. In the below example, when the annotation is used on a constructor, an instance of userService is injected as an argument to the constructor when UserController is created:
public class UserController {
private UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService= userService;
}
}
In simple words Autowiring, wiring links automatically, now comes the question who does this and which kind of wiring.
Answer is: Container does this and Secondary type of wiring is supported, primitives need to be done manually.
Question: How container know what type of wiring ?
Answer: We define it as byType,byName,constructor.
Question: Is there are way we do not define type of autowiring ?
Answer: Yes, it's there by doing one annotation, #Autowired.
Question: But how system know, I need to pick this type of secondary data ?
Answer: You will provide that data in you spring.xml file or by using sterotype annotations to your class so that container can themselves create the objects for you.
Standard way:
#RestController
public class Main {
UserService userService;
public Main(){
userService = new UserServiceImpl();
}
#GetMapping("/")
public String index(){
return userService.print("Example test");
}
}
User service interface:
public interface UserService {
String print(String text);
}
UserServiceImpl class:
public class UserServiceImpl implements UserService {
#Override
public String print(String text) {
return text + " UserServiceImpl";
}
}
Output: Example test UserServiceImpl
That is a great example of tight coupled classes, bad design example and there will be problem with testing (PowerMockito is also bad).
Now let's take a look at SpringBoot dependency injection, nice example of loose coupling:
Interface remains the same,
Main class:
#RestController
public class Main {
UserService userService;
#Autowired
public Main(UserService userService){
this.userService = userService;
}
#GetMapping("/")
public String index(){
return userService.print("Example test");
}
}
ServiceUserImpl class:
#Component
public class UserServiceImpl implements UserService {
#Override
public String print(String text) {
return text + " UserServiceImpl";
}
}
Output: Example test UserServiceImpl
and now it's easy to write test:
#RunWith(MockitoJUnitRunner.class)
public class MainTest {
#Mock
UserService userService;
#Test
public void indexTest() {
when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");
String result = new Main(userService).index();
assertEquals(result, "Example test UserServiceImpl");
}
}
I showed #Autowired annotation on constructor but it can also be used on setter or field.
The whole concept of inversion of control means you are free from a chore to instantiate objects manually and provide all necessary dependencies.
When you annotate class with appropriate annotation (e.g. #Service) Spring will automatically instantiate object for you. If you are not familiar with annotations you can also use XML file instead. However, it's not a bad idea to instantiate classes manually (with the new keyword) in unit tests when you don't want to load the whole spring context.
Keep in mind that you must enable the #Autowired annotation by adding element <context:annotation-config/> into the spring configuration file. This will register the AutowiredAnnotationBeanPostProcessor which takes care the processing of annotation.
And then you can autowire your service by using the field injection method.
public class YourController{
#Autowired
private UserService userService;
}
I found this from the post Spring #autowired annotation
I'm having a problem injecting mock into one class I need for testing. I'm trying to mock a Dao class and had no problem doing so using ReflectionTestUtils in various services I'm using, however this one just does not want to work, it keeps calling the Dao class and getting errors from the database.
This is the test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class DedicationControllerTest extends AbstractRestTest {
#Mock
UserDaoImpl userDao;
#Autowired
#InjectMocks
GrantedAuthoritiesLevelsHolder grantedAuthoritiesLevelsHolder;
#Test
public void shouldTest() throws Exception {
//given
String json = this.getJsonFromFile("json/my.json");
Mockito.when(userDao.getUser(Mockito.anyString())).thenReturn(new User(1l, "mock"));
ReflectionTestUtils.setField(grantedAuthoritiesLevelsHolder, "userDao", userDao);
ResultActions result = mockMvc.perform(post( controllerUrl + "/action")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(json));
// then
result
.andExpect(status().isOk());
}
}
And this is the class I'm trying to inject mock into:
#Component
#Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class GrantedAuthoritiesLevelsHolder {
#Autowired
private UserDao userDao;
// some methods
}
You will have to register mocked bean as UserDao when the context is getting loaded. You can register it as shown below. Put this in any class annotated with #Configuration
#Bean
#Primary
public UserDao UserDao() {
return mock(UserDao.class);
}
I believe that your configuration may be not enough to put a mock into Spring context.
My advice:
#MockBean(answer=Answers.RETURNS_SMART_NULLS)
UserDao userDao;
#Autowired
GrantedAuthoritiesLevelsHolder grantedAuthoritiesLevelsHolder;
It should put a mock into Spring context, moreover it should give you hints with incorrect/missing stubbing.
The class that I want to test is called UserService with sendEmail method, which sends an email to user.
To accomplish this task it depends on EmailService. Now when writing a testcase to test this - should I create UserService userService = new UserService() and mock Email service OR create context file define UserService bean there and #Autowired UserService in my test class and mock EmailService?
What is the difference between both approaches and when should i use one over the other? Which of these is a real object?
If your class is meant to be a bean, and for example you also have the expectation to get dependencies injected, you should not create instances with the new operator. Please check inject-doesnt-work-with-new-operator answer
You can create a TestConfig.class and mock the dependencies of the UserService (using a mock framework that you like - I prefer mockito). In this TestConfig, you create your bean:
#Configuration
public static class TestConfig {
#Bean
private EmailService emailService() {
return Mockito.mock(EmailService.class);
}
//Assuming that you have constructor injection.
#Bean
public UserService userService() {
return new UserService(emailService());
}
}
HelloController.java
#RestController
class HelloController {
#GetMapping(value = "{id}/hello")
public ModelAndView listAPI(#PathVariable("id") String profileId) {
ModelAndView mav = new ModelAndView();
return mav;
}
}
HelloControllerTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = HelloConfigTest.class)
class HelloControllerTest {
#Inject
private WebApplicationContext webApplicationContext;
#Inject
private Foo mockFoo
#InjectMocks
HelloController helloController;
private MockMvc mockMvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testHello() throws Exception {
mockMvc.perform(
get("/{id}/campaigns", "id1"))
.andExpect(status().isOk()));
}
}
// I have another test that directly calls the controller method.
// So I need #InjectMocks to get an instance of the controller
#Test
public void test2() {
when(mockFoo.getX()).thenReturn(true);
helloController.saveAPI();
}
HelloConfigTest.java
#Configuration
#ComponentScan("com.test.controller")
class HelloConfigTest {
#Bean
public mockFoo() {
return Mockito.mock(Foo.class);
}
}
The response that I get here is 404 and I expect 200.
But it works and I get 200 if I change #GetMapping to #RequestMapping(value="{id}/hello", method=RequestMethod.GET)
Am I missing anything here ?
Your configuration is extremely bare bones
#Configuration
#ComponentScan("com.test.controller")
class HelloConfigTest {
It doesn't register any Spring MVC infrastructure beans, either implicitly or explicitly.
When MockMvc, internally, creates a TestDispatcherServlet to test your #Controller class, it has to defer to some default Spring MVC infrastructure types.
Among these infrastructure types is HandlerMapping which is
to be implemented by objects that define a mapping between requests and handler objects.
The default implementation used by the TestDispatcherSerlet is DefaultAnnotationHandlerMapping (an old class) which looks for #RequestMapping specifically, it doesn't recursively do a meta-annotation lookup. Your #GetMapping annotated method is therefore not found and not registered as a handler.
If, instead, you configure your application context with #EnableWebMvc
#Configuration
#ComponentScan("com.test.controller")
#EnableWebMvc
class HelloConfigTest {
Spring will implicitly register a RequestMappingHandlerMapping, which does do this "recursive" lookup for the annotation hierarchy (called merging). Since #GetMapping is annotated with #RequestMapping, the annotated handler method will be found and registered.
As for the #InjectMocks, note that the instance referenced by the field is different from the one used to handle the request performed by the MockMvc object. The former is managed by Mockito, the latter by Spring.
How to intercept #RestController methods using MethodInterceptor in SpringBoot?
Prior to using springboot, I have a simple Interceptor that logs the execution time of a bean method. Simply intercepts all spring bean methods through a default proxy definition.
#Component
public class MethodTimer implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
final StopWatch stopWatch = new StopWatch();
stopWatch.start(methodInvocation.getMethod().toGenericString());
try {
return methodInvocation.proceed();
}
finally {
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
}
}
The spring configuration where com.mypackages contains the beans and the MethodInterceptor implementation.
<context:component-scan base-package="com.mypackages" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
The configuration above is loaded via
#ContextConfiguration("/application-context.xml")
Method executions are logged, everything seems to be working, life is good.
Moving to SpringBoot
I use the same code, switched to annotations (eliminating the *.xml) configuration
#SpringBootApplication(scanBasePackages = { "com.mypackages" })
#EnableAutoConfiguration
#EnableAspectJAutoProxy(proxyTargetClass=true)
Added a constructor to the MethodTimer with System.out.println() to make sure that the Interceptor has been loaded by spring boot
public MethodTimer() {
System.out.println("MethodTimer - Constructor");
}
And yes, it was loaded and created as "MethodTimer - Constructor" is found in the console logs.
However, none of the #RestController methods are intercepted. Below is a simple Rest Controller
#RestController
#RequestMapping("/test")
public class HelloWorldService {
#RequestMapping(method = RequestMethod.GET)
public String sayHello() {
System.out.println("Hello World!");
return "Hello World!";
}
}
Even tried creating a pure spring bean via #Component and #Autowired it in the #RestController to see if that pure spring bean is intercepted, but it was not intercepted as well.
A simple Test service bean. The test() method should be intercepted.
#Component
public class TestService {
public void test() {
System.out.println("TestService.test()");
}
}
Revised RestController
#RestController
#RequestMapping("/test")
public class HelloWorldService {
#Autowired
private TestService testService;
#RequestMapping(method = RequestMethod.GET)
public String sayHello() {
testService.test();
return "Hello World!";
}
}
Notes
The MethodTimer was loaded as the constructor was called showing the System.out.println log in the console, it seems however spring boot did not automatically determine that this bean/component is implementing MethodInterceptor.
The simple Spring Bean annotated with #Component bean was not intercepted.
The Rest Controller annotated with #RestController was not intercepted.
I have tried adding #Component, #Service in the RestController, it did not work.
I have tried tried #EnableAutoConfiguration, adding spring.aop.* configurations in the application.properties, did not work.
Tried using SpringBoot version 1.5.4.RELEASE, does not work.
I know I can always try to use Aspect as shown in the spring-boot-sample-aop example: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-aop
But not able to use previous spring code and configure it with springboot is just too lame. If MethodInterceptor and DefaultAdvisorAutoProxyCreator is not supported anymore in spring boot, it should have been deprecated