STACKJAVA

Spring Core – Phần 9: Spring Auto Component Scanning, Các annotation hay dùng trong Spring

Spring Core – Phần 9: Spring Auto Component Scanning, Các annotation hay dùng trong Spring

1. Spring Auto Component Scanning

Thông thường, chúng ta khai báo tất cả các bean hoặc component trong file XML để Spring container có thể tìm và quản lý các bean.

Thực tế, Spring có khả năng tự động tìm, dò và tạo thể hiện của bean từ các định nghĩa ban đầu ở package, class mà không cần phải khai báo chúng trong file XML.

(Cách này thường dùng với các class không lưu trạng thái – không có thuộc tính, mà chỉ chứa các method)

Ví dụ Ta có class UserService.java gọi tới class UserDAO.java

package stackjava.com.autoscancomponent.demo;

public class UserDAO {

  public void findUser(int id) {
    System.out.println("find user by id = " + id);
  }

}

package stackjava.com.autoscancomponent.demo;

public class UserService {

  private UserDAO userDAO;

  public void findUser(int id) {
    System.out.println("userService find:");
    userDAO.findUser(id);
  }

  public UserDAO getUserDAO() {
    return userDAO;
  }

  public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
  }
  
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <bean id="userService" class="stackjava.com.autoscancomponent.demo.UserService">
    <property name="userDAO" ref="userDAO" />
  </bean>
  <bean id="userDAO" class="stackjava.com.autoscancomponent.demo.UserDAO">
  </bean>

</beans>

Demo

package stackjava.com.autoscancomponent.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.findUser(1);
  }
}

Kết quả:

userService find:
find user by id = 1

 

Bây giờ ta chuyển sang dùng auto scan component:

package stackjava.com.autoscancomponent.demo;

import org.springframework.stereotype.Repository;

@Repository
public class UserDAO {

  public void findUser(int id) {
    System.out.println("find user by id = " + id);
  }

}
package stackjava.com.autoscancomponent.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

  @Autowired
  private UserDAO userDAO;

  public void findUser(int id) {
    System.out.println("userService find:");
    userDAO.findUser(id);
  }

}
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <context:component-scan base-package="stackjava.com.autoscancomponent.demo" />

</beans>

Demo

package stackjava.com.autoscancomponent.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.findUser(1);
  }
}

Kết quả:

userService find:
find user by id = 1

Rõ ràng cách viết này nhanh chóng hơn việc phải khai báo beans trong file XML rất nhiều.

Mình sẽ giải thích một số đoạn code trong ví dụ trên:

<context:component-scan base-package=”stackjava.com.autoscancomponent.demo” />: đánh dấu rằng spring container sẽ dò tìm (scan) tất cả các class trong package này để tìm các component.

Các Annotation:

Vậy khi nào dùng  @Repository,@Service hay @Controller?
Thực ra cả 4 annotation này chỉ dùng với mục đích đánh đấu là auto component scan, bạn có thể dùng chúng lẫn lộn, hoặc nếu không rõ class đang ở tầng persistence, business hay presentation thì cứ dùng @Component nó vẫn hoạt động.

Tuy nhiên bạn nên dùng các annotation  @Repository,@Service hay @Controller một cách phân biêt, phù hợp với các tầng chức năng của nó, như thế code của bạn sẽ dễ hiểu, dễ đọc hơn.

Lưu ý, mặc định bean được tạo từ auto scan component có tên là tên của class với chữ đầu tiên viết thường.

Ví dụ: UserService -> userService, UserDAO -> userDAO

Bạn có thể đổi tên của bean khi thực hiện scan bằng cách chỉ rõ tên của nó bên cạnh Annotation.

Ví dụ:

@Service("service1")
public class UserService {

  @Autowired
  private UserDAO userDAO;

  public void findUser(int id) {
    System.out.println("userService find:");
    userDAO.findUser(id);
  }

}

Khi lấy bean ta sẽ lấy theo tên được chỉ rõ là “service1”

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("service1");
userService.findUser(1);

 

Annotation @Autowired: được dùng để thực hiện 1 bean/thuộc tính khác vào đối tượng hiện tại (thuộc tính được inject vào cũng phải là 1 auto scan component hoặc được khai báo bean trong file config)

(Xem lại về annotation @Autowired trong Spring tại đây)

 

Okay, Done!

Download code ví dụ trên tại đây

 

References:

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html

https://www.concretepage.com/spring/spring-auto-detection-with-component-service-repository-and-controller-stereotype-annotation-example-using-componentscan-and-component-scan