Let's summarize the reasons why constructor injection is recommended

Constructor injection and field injection

Advantages and disadvantages of field injection

Implementation example with field injection


@Service
public class BookService{
    
    @Autowired
    private BookDao bookDao;
    
    @Autowired
    private HogeDao hogeDao;

    /**
     *Returns a Book that matches the argument bookId
     */
    public Book selectById(int bookId){
        Optional<Book> wrappedBook = bookDao.findById(bookId);
        return wrappedBook.orElseThrow(() -> NotFoundException("No"));
    }
                          .
                          .
                          .
}

Advantages and disadvantages of constructor injection

Implementation example in constructor injection

@Service
public class BookService{
    private final BookDao bookDao;
    private final HogeDao hogeDao;
    
    @Autowired // → Spring4.This annotation can be omitted if it is 3 or more
    public BookService(BookDao bookDao, HogeDao hogeDao){
        this.bookDao = bookdao;
        this.hogeDao = hogedao;
    }

    /**
     *Returns a Book that matches the argument bookId
     */
    public Book selectById(int bookId){
        Optional<Book> wrappedBook = bookDao.findById(bookId);
        return wrappedBook.orElseThrow(() -> NotFoundException("No"));
    }
                          .
                          .
                          .
}

Improved testability by constructor injection

When testing a class implemented by field injection

@RunWith(SpringRunner.class)
@SpringBootTest
public class BookServiceTests{

    @Autowired    
    private BookService bookService;

    @MockBean
    private BookDao bookDao;

    @MockBean
    private HogeDao hogeDao;

 
    @Test
public void Being able to get books with the specified bookId(){
        // setUp
        var expected = new Book(1, "Book name"); 
        when(bookDao.findById(1)).thenReturn(expected);
        var bookService = new BookService();

        // execute
        var actual = bookService.selectById(1);

        // verify
        assertThat(...Omitted below
    }
}

When testing a class implemented by constructor injection


public class BookServiceTests{ 
    private BookService bookService;
    private BookDao bookDao;
    private HogeDao hogeDao;

    @Before
    public void setUp(){
        bookDao = Mockito.mock(BookDao.class);
        hogeDao = Mockito.mock(HogeDao.class);
        bookService = new BookService(bookDao, hogeDao);
    }
 
    @Test
public void Being able to get books with the specified bookId(){
        // setUp
        var expected = new Book(1, "Book name"); 
        when(bookDao.findById(1)).thenReturn(expected);
        var bookService = new BookService();

        // execute
        var actual = bookService.selectById(1);

        // verify
        assertThat(...Omitted below
    }
}

@RunWith(MockitoJUnitRunner.class)
public class BookServiceTests{ 
    private BookService bookService;

    @Mock
    private BookDao bookDao;
    @Mock
    private HogeDao hogeDao;

    @Before
    public void setUp(){
        bookService = new BookService(bookDao, hogeDao);
    }
    //Omitted below

reference

Recommended Posts

Let's summarize the reasons why constructor injection is recommended
What is the constructor for?
Spring Autowired is written in the constructor
What is JSP? ~ Let's know the basics of JSP !! ~
Exception silence is the worst (why programmers silence exceptions?)