Bộ sưu tập

Bean Wiring – các cách để liên kết các thành phần trong Spring


https://codersontrang.com/2013/01/25/bean-wiring-cac-cach-de-lien-ket-cac-thanh-phan-trong-spring/

Trong bài viết “Giới thiệu về Spring framework” chúng ta đã được biết qua một số khái niệm, tư tưởng của Spring trong việc khởi tạo và liên kết các thành phần trong một ứng dụng lại với nhau. Bean Wiring (hay còn gọi là Dependency Injection) là thuật ngữ dùng để chỉ quá trình các thành phần được liên kết với nhau qua Spring. Bài viết này xin được tổng hợp và giới thiệu tới bạn đọc một số cách mà các thành phần có thể được liên kết với nhau trong Spring. Nên nhớ thông tin cho việc liên kết các thành phần sẽ được khai báo trong file cấu hình (.xml), vì thế trong bài viết này, chúng ta sẽ tập trung phần lớn vào nội dung của file cấu hình là các đoạn mã XML.

Như đã biết, Spring dùng thẻ <bean> để khởi tạo một thành phần. Trong một thành phần này, có thể có nhiều thuộc tính tham chiếu đến khác thành phần khác được quản lý bởi Spring container. Bình thường, nếu như không dùng Spring, một thuộc tính sẽ được khai báo để tham chiếu đến một giá trị/đối tượng nào đó qua contructor hoặc phương thức setXXX() tương ứng với thuộc tính đó. Tương tự, Spring cũng cung cấp đầy đủ các cách khai báo để liên kết các thành phần qua Contructor hoặc các phương thức setter.

Ví dụ ta có lớp Student như sau:


package com.wordpress.hautudu.beanwiring;  
 public class Student {  
      private int age;  
      private String name;  
      private Address address;  

      public Student(){}  

      public Student(int age, String name, Address address){  
           this.age = age;  
           this.name = name;  
           this.address = address;  
      }  

      public int getAge() {  
           return age;  
      }  
      public void setAge(int age) {  
           this.age = age;  
      }  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
      public Address getAddress() {  
           return address;  
      }  
      public void setAddress(Address address) {  
           this.address = address;  
      }  
 }  

Và lớp Address như sau:


 package com.wordpress.hautudu.beanwiring;  
 public class Address {  
      private String district;  
      private String street;  
      private int houseNumber;
  
      public String getDistrict() {  
           return district;  
      }  
      public void setDistrict(String district) {  
           this.district = district;  
      }  
      public String getStreet() {  
           return street;  
      }  
      public void setStreet(String street) {  
           this.street = street;  
      }  
      public int getHouseNumber() {  
           return houseNumber;  
      }  
      public void setHouseNumber(int houseNumber) {  
           this.houseNumber = houseNumber;  
      }  
 }  

Hai thành phần trên có thể được liên kết với nhau như sau:

I. Liên kết qua constructor
Khi không sử dụng Spring


Address address = new Address();  
 ...  
Student student = new Student(18, "Nguyen Van A", address); 

Tương đương khi sử dụng Spring, ta làm như sau:


<bean id="addressBean" class="com.wordpress.hautudu.beanwiring.Address">  
     ...  
</bean>  
<bean id="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
     <constructor-arg value="18"/>  
     <constructor-arg value="Nguyen Van A"/>  
     <constructor-arg ref="addressBean"/>  
</bean> 

  • Ta sử dụng thẻ <constructor-arg> để thể hiện cho một tham số của constructor.
  • Nếu tham số thuộc kiểu primitive (int, float, double, String…) thì ta sử dụng thuộc tính value để chỉ ra giá trị cho tham số. Nếu tham số thuộc kiểu tham chiếu, ta sử dụng thuộc tính ref để chỉ ra đối tượng mà tham số tham chiếu đến
  • Thứ tự của các thẻ <constructor-arg> phải giống với thứ tự của các tham số bên trong constructor

II. Liên kết qua các phương thức setter
Bình thường với mỗi thuộc tính XXX trong một lớp, sẽ có các phương thức getXXX() và setXXX() tương ứng với nó. Qua phương thức setXXX(), thuộc tính XXX sẽ được gán cho một giá trị nào đó (giá trị này có thể thuộc kiểu primitive hay kiểu tham chiếu). Spring cũng cung cấp cho chúng ta phương pháp để gán giá trị đến một thuộc tính qua phương thức setter của nó. Cụ thể như trong ví dụ trên, ta có thể làm như sau và vẫn có kết quả tương tự


<bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
     <property name="age" value="24"/>  
     <property name="name" value="Nguyen Van A"/>  
     <property name="address" ref="addressBean"/>  
</bean>

  • Thẻ <property> được dùng để biểu diễn cho một phương thức setter. Thuộc tính name của thẻ phải khớp với phần đuôi của phương thức setter. Ví dụ ta có phương thức là setAField(), thì lúc khai báo sẽ tương ứng là name=”aField”.
  • Ta cũng sử dụng lần lượt hai thuộc tính valueref cho việc gán một giá trị thuộc kiểu primitive hay thuộc kiểu tham chiếu một cách tương ứng.

III. Liên kết đến một inner bean
Một inner bean được khai báo để khởi tạo bên trong nội dung khai báo của một bean khác. Để ý trong ví dụ của chúng ta, thuộc tính address được tham chiếu đến một bean là addressBean. addressBean ở đây không phải là một inner bean bởi vì nó được khai báo ở bên ngoài và ngang hàng với các bean khác. Tuy nhiên như ví dụ ở trên, ta có thể thay thế addressBean bằng một inner bean như sau

Trong trường hợp liên kết qua constructor


<bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
     <constructor-arg value="24"/>  
     <constructor-arg value="Nguyen Van A"/>  
     <constructor-arg>  
          <bean class="com.wordpress.hautudu.beanwiring.Address">  
               ...  
          </bean>  
     </constructor-arg>  
</bean> 

Trong trường hợp liên kết qua phương thức setter


 <bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
      <property name="age" value="24"/>  
      <property name="name" value="Nguyen Van A"/>  
      <property name="address">  
           <bean class="com.wordpress.hautudu.beaninwiring.Address">  
                ...  
           </bean>  
      </property>  
 </bean>

  • Không nhất thiết phải chỉ ra name cho một inner bean
  • Phạm vi của inner bean chỉ giới hạn ở trong vùng nó được khai báo để khởi tạo.

IV. Liên kết trong trường hợp các thuộc tính thuộc kiểu Collection
Các thuộc tính thuộc kiểu Collection là các thuộc tính mà bản thân nó là một tập hợp của các phần tử khác. Trong Java, một thuộc tính như thế có thể thuộc kiểu List, Set, Map và Properties. Trong ví dụ trên, ta sẽ thêm vào lớp Student để nó có thêm một số thuộc tính thuộc kiểu Collection như sau:

Student.java


 package com.wordpress.hautudu.beanwiring;  
 
 import java.util.List;  
 import java.util.Map;  
 import java.util.Properties;  

 public class Student {  
      private int age;  
      private String name;  
      private Address address;  
      List<String> books;  
      Map<String, Subject> timeTable;  
      Properties hobbies; 
 
      public Student(){}  
      public Student(int age, String name, Address address) {  
           this.age = age;  
           this.name = name;  
           this.address = address;  
      }  

      public Properties getHobbies() {  
           return hobbies;  
      }  
      public void setHobbies(Properties hobbies) {  
           this.hobbies = hobbies;  
      }  
      public Map<String, Subject> getTimeTable() {  
           return timeTable;  
      }  
      public void setTimeTable(Map<String, Subject> timeTable) {  
           this.timeTable = timeTable;  
      }  
      public List<String> getBooks() {  
           return books;  
      }  
      public void setBooks(List<String> books) {  
           this.books = books;  
      }  
      public int getAge() {  
           return age;  
      }  
      public void setAge(int age) {  
           this.age = age;  
      }  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
      public Address getAddress() {  
           return address;  
      }  
      public void setAddress(Address address) {  
           this.address = address;  
      }  
 } 

1. Liên kết cho các thuộc tính thuộc kiểu List, Set
Trong ví dụ trên, ta có thuộc tính books là một List tên các quyển sách. Ta có thể khai báo để khởi tạo danh sách này trong Spring như sau:


 <bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
      ...  
      <property name="books">  
           <list>  
                <value>Book1</value>  
                <value>Book2</value>  
                <value>Book3</value>  
           </list>  
      </property>  
      ...  
 </bean>

  • Dùng thẻ <list> hoặc <set> để chỉ ra thuộc tính là thuộc kiểu List, hay Set
  • Dùng thẻ <value> để gán giá trị cho từng phần tử của list (set) trong trường hợp các phần tử thuộc kiểu primitive. Nếu các phần tử của list (set) là thuộc kiểu tham chiếu thì ta sẽ dùng thẻ <ref bean=”referencedBeanName” /> thay cho thẻ <value>
  • Trong trường hợp trên, ta hoàn toàn có thể sử dụng thẻ <set> để thay cho thẻ <list>. Lúc đó các phần tử bên trong thuộc tính books sẽ là duy nhất, không bị lặp lại.

2. Liên kết cho các thuộc tính thuộc kiểu Map
Thuộc tính kiểu Map là một tập hợp các phần tử được lưu dưới dạng keyvalue. Mỗi một cặp key và value sẽ được gọi là một entry. Thuộc tính timeTable trong trường hợp trên là một ví dụ về một thuộc tính kiểu Map mà trong đó key thuộc kiểu String, còn value thuộc kiểu tham chiếu Subject như sau:


 package com.wordpress.hautudu.beanwiring;  
 public class Subject {  
      private String name;  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
 } 

Ta có thể khai báo các phần tử trong Map timeTable này qua Spring như sau:


 <bean name="mathSubjectBean" class="com.wordpress.hautudu.beanwiring.Subject">  
      <property name="name" value="Math"/>  
 </bean>  

 <bean name="physicSubjectBean" class="com.wordpress.hautudu.beanwiring.Subject">  
      <property name="name" value="Physic"/>  
 </bean>  

 <bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
      ...  
      <property name="timeTable">  
           <map>  
                <entry key="Monday" value-ref="mathSubjectBean"/>  
                <entry key="Tuesday" value-ref="physicSubjectBean"/>  
           </map>  
      </property>  
      ...  
 </bean>

  • Dùng thẻ <map> để chỉ ra đây là một thuộc tính kiểu Map
  • Mỗi một phần tử của Map sẽ được biểu diễn bởi một thẻ <entry>.
  • Trong thẻ <entry>, thuộc tính key (hoặc key-ref) sẽ được dùng để gán giá trị cho key thuộc kiểu primitive (hoặc kiểu tham chiếu)
  • Trong thẻ <entry> thuộc tính value (hoặc value-ref) sẽ được dùng để gán giá trị thuộc kiểu primitive (hoặc kiểu tham chiếu) cho value tương ứng với key trong entry.

3. Liên kết cho các thuộc tính thuộc kiểu Properties
Một thuộc tính thuộc kiểu Properties cũng tương tự như một thuộc tính thuộc kiểu Map, tức là nó cũng là một tập hợp các phần tử ở dưới dạng key và value. Trong ví dụ, thuộc tính hobbies là một trong những thuộc tính như vậy. Một ví dụ về cách khởi tạo thuộc tính kiểu này sẽ giống như ở dưới đây:


 <bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
     ...  
      <property name="hobbies">  
           <props>  
                <prop key="music">Jazz, Rock</prop>  
                <prop key="TVShow">News, Games</prop>  
           </props>  
      </property>  
     ...  
 </bean>

  • Dùng thẻ <props> để chỉ ra đây là thuộc tính thuộc kiểu Properties
  • Dùng thẻ <prop> để chỉ ra một phần tử là một cặp key và value. Thuộc tính key của thẻ này sẽ chỉ ra giá trị cho key của phần tử, và value tương ứng với key sẽ nằm trong phần thân của thẻ <prop>

Nhìn lại tổng thể qua ví dụ
Như vậy ta đã biết được các cách cơ bản để khởi tạo và liên kết các thành phần bằng việc khai báo trong file cấu hình của Spring. Bây giờ sẽ là lúc nhìn lại toàn bộ mọi thứ một cách tổng quát qua ví dụ của chúng ta. Các file Student.java, Address.java, Subject.java sẽ giống như ở trên. Dưới đây sẽ chỉ là source code đầy đủ cho file cấu hình beans.xml và lớp BeanWiringTest.java có chứa phương thức main() để chạy chương trình. (cấu trúc của ví dụ này cũng sẽ giống hệt như cấu trúc của ví dụ trong bài viết “Giới thiệu về Spring framework”)

beans.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"  
 xsi:schemaLocation="http://www.springframework.org/schema/beans  
 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">  

      <bean name="addressBean" class="com.wordpress.hautudu.beanwiring.Address">  
           <property name="district" value="Ha Noi"/>  
           <property name="street" value="Pham Hung"/>  
           <property name="houseNumber" value="889"/>  
      </bean>  

      <bean name="mathSubjectBean" class="com.wordpress.hautudu.beanwiring.Subject">  
           <property name="name" value="Math"/>  
      </bean>  

      <bean name="physicSubjectBean" class="com.wordpress.hautudu.beanwiring.Subject">  
           <property name="name" value="Physic"/>  
      </bean>  

      <bean name="studentBean" class="com.wordpress.hautudu.beanwiring.Student">  
           <property name="age" value="24"/>  
           <property name="name" value="Nguyen Van A"/>  
           <property name="address" ref="addressBean"/>  

           <property name="books">  
                <list>  
                     <value>Book1</value>  
                     <value>Book2</value>  
                     <value>Book3</value>  
                </list>  
           </property>       

           <property name="timeTable">  
                <map>  
                     <entry key="Monday" value-ref="mathSubjectBean"/>  
                     <entry key="Tuesday" value-ref="physicSubjectBean"/>  
                </map>  
           </property>  

           <property name="hobbies">  
                <props>  
                     <prop key="music">Jazz, Rock</prop>  
                     <prop key="TVShow">News, Games</prop>  
                </props>  
           </property>  
      </bean>  
 </beans>

BeanWiringTest.java


 package com.wordpress.hautudu.beanwiring;  

 import java.util.Map.Entry;  
 import org.springframework.beans.factory.BeanFactory;  
 import org.springframework.context.ApplicationContext;  
 import org.springframework.context.support.ClassPathXmlApplicationContext;  

 public class BeanWiringTest {  
      public static void main(String [] args){  
           ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");  
           BeanFactory factory = (BeanFactory) context;  
           Student studentBean = (Student) factory.getBean("studentBean");
  
           System.out.println("Student age: "+studentBean.getAge());  
           System.out.println("Student name: "+studentBean.getName());  
           System.out.println("Student district: "+studentBean.getAddress().getDistrict());  
           System.out.println("Student street: "+studentBean.getAddress().getStreet());  
           System.out.println("Student house number: "+studentBean.getAddress().getHouseNumber()); 
 
           System.out.println("Book list: ");  
           for(String book : studentBean.getBooks()){  
                System.out.println(book);  
           }
  
           System.out.println("Time table: ");  
           for(Entry<String, Subject> entry : studentBean.getTimeTable().entrySet()){  
                System.out.println(entry.getKey()+" - "+entry.getValue().getName());  
           }
  
           System.out.println("Hobbies: ");  
           for(Object key : studentBean.getHobbies().keySet()){  
                System.out.println(key +" - "+studentBean.getHobbies().getProperty((String) key));  
           }  
      }  
 }

Kết quả khi chạy chương trình trên sẽ giống như hình dưới đây

basic_bean_wiring

Bài viết hi vọng bạn đọc sẽ có được các cách thức cơ bản nhất để khởi tạo và liên kết các thành phần bằng việc khai báo thông tin trong file cấu hình của Spring. Nói là cơ bản có nghĩa là mọi thứ mới chỉ là bắt đầu :), các vấn đề liên quan đến việc bean wiring sẽ còn được nhắc đến trong các bài viết sau.

Good luck!

Advertisements
By Coder Sơn Trang Posted in Spring

9 comments on “Bean Wiring – các cách để liên kết các thành phần trong Spring

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s