Saturday, May 31, 2014

Giới thiệu về Spring Framework

Giới thiệu về Spring Framework

Spring là một application framework mã nguồn mở, được giới thiệu vào năm 2002. Rod Johnson đã đưa ra ý tưởng này từ kinh nghiệm làm việc với kiến trúc J2EE.


Ông ta đã viết cuốn sách với tiêu đề: “J2EE Develoment without using EJB” để giới thiệu khái niệm trình chứa hạng nhẹ (lightweight container). Với lý luận: EJB thì có giá trị của nó, nhưng không phải lúc nào cũng cần thiết và phù hợp cho tất cả các ứng dụng.

Như Hibernate chống lại CMP về nguyên lý cơ bản của kỹ thuật ORM, Spring chống lại EJB vì sự phức tạp và không phù hợp cho các unit test. Thay vì EJB, Spring sử dụng Java bean, với một vài sự thay đổi để thu được tất cả các thuận lợi mà môi trường EJB đưa ra. Do đó Spring là một sự lựa chọn khác so với EJB.

Spring không phải là một kỹ thuật persistence nhưng nó cho phép tích hợp với các kỹ thuật khác. EJB thì tập trung vào kỹ thuật persistence và bây giờ nó đã cộng tác với Hibernate, một ORM tốt nhất ngày nay. Nó đang dự định cộng tác với một kỹ thuật ORM tốt khác là JDO (cung cấp cho Object Database).

Trong Spring, chúng ta có thể sử dụng Java Bean để rút trích các thứ mà lúc trước chỉ có thể với EJB. Mục tiêu chính của Spring là đơn giản việc phát triển J2EE và testing.

EJB được xuất hiện vào 1988 và là một chuẩn, đặc tả trong thế giới Enterprise. Mặc dù có một số kỹ thuật Java gần đây, nhưng không có kỹ thuật nào đáng kể so với EJB về mặc tổng các đặc tính của nó.

Theo Rod Johnson thì EJB không phức tạp nhưng nó cố gắng cung cấp cách giải quyết cho các vấn đề phức tạp. EJB được phát triển chính cho các giao dịch, đối tượng được phân phát ở trên máy khác. Nhưng một số enterprise project không có mức độ phức tạp và vẫn sử dụng EJB và thậm chí các ứng dụng đơn giản trở nên phức tạp. Trong trường hợp này thì Spring là một sự chọn lựa.

Từ lúc Spring hỗ trợ các dịch vụ ở mức enterprise, thì nó tuyên bố là một sự lựa chọn khác đối với EJB.

Thuận lợi của EJB:

Transaction Management
Declarative Transaction support
Persistence ( CMP & BMP)
Declarative Security
Distributed Computing (Container managed RPC)

Spring không cố gắng làm mọi thứ nhưng nó hỗ trợ những kỹ thuật tốt nhất cho mỗi yêu cầu.Thay vì CMP & BMP, nó hỗ trợ một vài kỹ thuật persistence khác như JDO, Hiberbate và OJB. Các ORM tool này thì có nhiều khả năng cài đặt hơn CMP. Để đơn giản coding JDBC, có một tool là iBatis và Spring cũng hỗ trợ nó.

Spring sử dụng Acegi, một security framework mã nguồn mở và cung cấp để khai báo security thông qua cấu hình Spring hoặc class metadata, trong khi EJB khai báo security được cấu hình thông qua mô tả demployment. Spring cung cấp proxying cho RMI (kỹ thuật remoting đặc biệt như Burlap) JAX-RPC & web-service, trong khi EJB cung cấp lời gọi phương thức ở xa được quản lý bởi container.

Spring có thể cung cấp khai báo transaction như EJB. Hơn nữa, Spring còn cung cấp khai báo thủ tục rollback cho các phương thức và exception.

Do đó, trong khi EJB thì cứng và cố gắng làm mọi thứ, một vài công việc tốt nhưng một số thì không. Spring chỉ sử dụng Java Bean và thông qua một số kỹ thuật đặc biệt để cung cấp nhiều chức năng như EJB, bằng cách tích hợp với một số kỹ thuật open source khác.

Do đó, nó cung cấp một vài thuận lợi hơn EJB như:

Testing dễ dàng hơn - không cần khởi động EJB container để test.
Spring dựa vào quy ước của chuẩn Java Bean, nên programmer dễ dàng làm việc với nó.
Nó sử dụng AOP (Aspect-Oriented Programming), mô hình hữu ích để bổ sung vào OOP truyền thống và bảo toàn tính nguyên vẹn của OOP.
Nó thì uyển chuyển.

Mục đích của Spring là trở thành một application framework. Các framework phổ biến khác như Struts, Tapestry, JSF,... là các framework tốt cho tầng web nhưng khi chúng ta sử dụng các framework này, chúng ta phải cung cấp thêm framework khác để giải quyết tầng enterprise mà tích hợp tốt với các framework này. Spring làm giảm bớt vấn đề này bằng cách cung cấp một framework toàn diện bao gồm:

Core bean container,
MVC framework,
AOP integration framework,
JDBC integration framework,
EJB integration framework.

Nó cũng cung cấp module tích hợp với O/R tool như Hibernate và JDO. Do đó Spring framework có thể được xem như một kiến trúc chứa 7 module. Chức năng của mỗi thành phần như sau:

1. Core Container:
Core container cung cấp chức năng cơ bản của Spring. Thành phần chính của nó là Bean Factory, một cài đặt của Factory pattern. BeanFactory áp dụng IoC pattern để đặc tả sự phụ thuộc từ code của ứng dụng.

2. Spring Context/Application Context:
Spring context là một file cấu hình để cung cấp thông tin ngữ cảnh của Spring. Spring context cung cấp các service như JNDI access, EJB integration, e-mail, internalization, validation, và scheduling functionality.

3. Spring AOP (Aspect-Oriented):
Spring AOP module tích hợp chức năng lập trình hướng khía cạnh vào Spring framework thông qua cấu hình của nó. Spring AOP module cung cấp các dịch vụ quản lý giao dịch cho các đối tượng trong bất kỳ ứng dụng nào sử dụng Spring. Với Spring AOP chúng ta có thể tích hợp declarative transaction management vào trong ứng dụng mà không cần dựa vào EJB component.

Spring AOP module cũng đưa lập trình metadata vào trong Spring. Sử dụng cái này chúng ta có thể thêm annotation vào source code để hướng dẫn Spring nơi và làm thế nào để liên hệ với aspect.

4. Spring DAO:
Tầng JDBC và DAO đưa ra một cây phân cấp exception để quản lý kết nối đến database, điều khiển exception và thông báo lỗi được ném bởi vendor của database. Tầng exception đơn giản điều khiển lỗi và giảm khối lượng code mà chúng ta cần viết như mở và đóng kết nối. Module này cũng cung cấp các dịch vụ quản lý giao dịch cho các đối tượng trong ứng dụng Spring.

5. Spring ORM:
Spring có thể tích hợp với một vài ORM framework để cung cấp Object Relation tool bao gồm: JDO, Hibernate, OJB và iBatis SQL Maps.

6. Spring Web module:
Nằm trên application context module, cung cấp context cho các ứng dụng web. Spring cũng hỗ trợ tích hợp với Struts, JSF và Webwork. Web module cũng làm giảm bớt các công việc điều khiển nhiều request và gắn các tham số của request vào các đối tượng domain.

7. Spring MVC Framework:
MVC Framework thì cài đặt đầy đủ đặc tính của MVC pattern để xây dựng các ứng dụng Web. MVC framework thì cấu hình thông qua giao diện và chứa được một số kỹ thuật view bao gồm: JSP, Velocity, Tiles và generation of PDF và Excel file.

Ví dụ:
Có một số kỹ thuật tuyệt vời cho tầng web như: Spring MVC framework, Struts, JSF, WebWork, JSP, Tapestry, FreeMarker,...Developer sẽ bị lúng túng đối chiếu những điểm mạnh và xấu của tất cả chúng. Mỗi khi họ chọn một kỹ thuật và bắt đầu cài đặt, thì sau đó nếu họ muốn thay đổi một kỹ thuật khác thì rất khó. Nhưng Spring đưa ra các module cho tất cả các kỹ thuật trên, và rất đơn giản để thay đổi file cấu hình.

Với phương pháp này, nó có khả năng cho cả team thử và test các tất cả các hình thức trên và xem ảnh hưởng cùng tốc độ trước khi quyết định chọn lựa.

JSP là một view template mặc định. "InternalResouceViewResolver" có thể được sử dụng cho mục đích này
Như mình tìm hiểu thì Spring framework là một platform hổ trợ lập trình ứng dụng bằng java. Nó được phát minh bởi Rod Johnson. Nó được giới thiệu lần đầu tiên trong cuốn Expert One-on-One J2EE Design and Development, vào năm 2002. Spring đảm nhiệm(xử lý) phần cơ sở hạ tầng của phần mềm để bạn có thể tập trung vào xây dựng ứng dụng của mình.

Spring cho phép chúng ta xây dựng ứng dụng từ POJOs.
POJOs là viết tắt của "plain old Java objects" chỉ những object java bình thường, chúng không có gì đặc biệt, nó không theo một mô hình hay quy ước nào cả chỉ bao gồm các thuộc tính và phương thức.
1. Core package là phần cơ bản nhất của framework, cung cấp những đặc tính IoC và Dependency Injection. Khái niệm cơ bản là BeanFactory - cài đặt factory pattern cho phép bạn móc nối sự phụ thuộc giữa các đối tượng trong file cấu hình. (IoC và Dependency Injection mình sẽ giải thik sau )
2. Phía trên của Core package là Context package - cung cấp cách để truy cập đối tượng. Context package kết thừa các đặc tính từ bean package và thêm vào chức năng đa ngôn ngữ (I18N), truyền sự kiện, resource-loading,...
3. DAO package cung cấp cho tầng JDBC, bỏ bớt những coding dài dòng của JDBC và chuyển đổi mã lỗi được xác định bởi database vendor. JDBC package cung cấp cách lập trình tốt như declarative transaction management, không chỉ cho các lớp cài đặt các giao tiếp đặc biệt mà còn cho tất cả POJO (plain old Java objects).
4. ORM package cung cấp tầng tích hợp với object-relational mapping API bao gồm: JDO, Hibernate, iBatis. Sử dụng ORM package bạn có thể sử dụng tất cả các O/R mapper đó kết hợp với tất cả các đặc tính của Spring như declarative transaction management.
5. Spring AOP package cung cấp aspect-oriented programming cho phép bạn định nghĩa method-interceptor và pointcut để móc nối các chức năng được cài đặt trong các module. Sử dụng chức năng metadata bạn có thể kết hợp tất cả thông tin vào code.
6. Spring Web package cung cấp đặc tính của web như: chức năng file-upload, khởi tạo IoC container sử dụng trình lắng nghe serlvet và web-oriented application context. Package này để tích hợp với WebWork và Struts.
7. Spring MVC package cung cấp mô hình MVC cho ứng dụng web. Spring MVC framework cung cấp sự phân biệt rõ ràng giữa domain model và web form - cho phép bạn sử dụng tất cả các đặc tính khác của Spring framework.

src : http://khoinguonit.com/f40/hoc-spring-framework-1110/
Bây giờ mình sẽ nói về Inversion of Control(IoC) và Dependency Injection (DI). Đây là hai pattern quan trọng cần phải hiểu trong lập trình với Spring .
Đặt vấn đề :
Trong quá trình lập trình hướng đối tượng khi chúng ta xây dựng các ứng dụng với rất nhiều class. Khi đó thường xảy ra sự phụ thuộc giữa các class với nhau. Để giễ hiểu chúng ta có thể xét ví dụ sau :
Giả sử chúng ta có class XeMay chứa một đối tượng của class DongCo. 

class XeMay{
private DongCo dongco;
public XeMay(){
dongco = new DongCo();
}
}

Vấn đề cần quan tâm ở đây là ta có thể thấy có sự móc nối của hai class này. Ta có thể thấy class XeMay phụ thuộc vào đối tượng “dongco”. Một số vấn đề cần nói ở đây là :
- class XeMay đảm nhiệm (control ) việc tạo ra đối tượng động cơ.
- Đối tượng của class DongCo được tham chiếu trực tiếp từ class XeMay. Tạo tight coupling(kết nối cứng) giửa DongCo và XeMay.
- class XeMay biết rỏ kiểu của DongCo. Nhưng giả sử khi chúng ta muốn thay đổi DongCo theo kiểu DongCoPhunXang, DongCoHaiKy, … thì chúng ta phải sửa lại class XeMay.
Để giải quyết vấn đề này thì người ta đưa ra một giải pháp gọi là Inversion of Control . Giải pháp là thay vì class XeMay tạo ra đối tượng của class DongCo thì chúng ta sẻ truyền nó vào cho class XeMay. Nghĩa là chúng ta thay đổi trách nhiệm tạo đối tượng "dongco" của class XeMay cho một thành phần nào đó bên ngoài(nên phương pháp này mới được gọi là IoC).

class XeMay{
private DongCo dongco;
public XeMay(DongCo dc){
dongco = dc;
}
public inserDongCo(DongCo dc){
dongco = dc;
}
}
Ở đây ta có một nguyên lý cần quan tâm đó là class chính chứa các đối tượng của class khác thì không nên phụ thuộc trực tiếp vào các class đó. Mà nên để class chính phụ thuộc vào interface hoặc abstract class của các class thành phần. Như trường hợp này thì DongCo nên là một interface của các loại động cơ khác. Khi đó chúng ta có thể truyền cho class XeMay bất kì loại động cơ nào mà không cần phải sửa code trong class XeMay.
Ví dụ : xemay = new XeMay(new DongCoBonKy());
hoặc : xemay.insertDongCo(new DongCoHaiKy());
Từ đầu đến giờ mình không nhắc đến Dependency injection là vì hai pattern này gần như tương tự nhau( không biết có phải là một ko ). Có thể dịch sơ sơ DI là tiêm vào sự phụ thuộc . Ta có thể thấy trong ví dụ thì đối tượng của class DongCo được truyền vào (tiêm vào) cho class XeMay.
package example.com;

public class XeMay {
private DongCo dongco;

public XeMay(DongCo dongco){
this.dongco = dongco;
}

public String XeNoMay(){
return dongco.NoMay();
}

public DongCo getDongco() {
return dongco;
}

public void setDongco(DongCo dongco) {
this.dongco = dongco;
}

}

package example.com;

public interface DongCo {
public String NoMay();
}

package example.com;

public class DongCoHaiKy implements DongCo {

@Override
public String NoMay() {
return "brum brum brum, hello world....";

}

}

package example.com;

public class DongCoBonKy implements DongCo {

@Override
public String NoMay() {

return "ye yae ye yee, hello wooorld......";

}

}

package example.com;

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

public class App {

public static void main(String[] args){

ApplicationContext context = 
new ClassPathXmlApplicationContext("beans.xml");

XeMay xehaiky = (XeMay) context.getBean("xebonky");
XeMay xebonky = (XeMay) context.getBean("xehaiky");

System.out.println(xehaiky.XeNoMay());
System.out.println(xebonky.XeNoMay());
}

}

Và phần cuối cùng củng là quan trọng nhất đó là các bạn viết file để cấu hình cho các thành phần
Nhấp chuột phải vào Src chọn New -> Other sau đó chọn như hình :
Chúng ta đặt tên cho file này là “beans.xml” và pass nội dung này vào :

<?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.xsd">

<bean id="dongcohaiky" class="example.com.DongCoHaiKy"></bean>
<bean id="dongcobonky" class="example.com.DongCoBonKy"></bean>

<bean id="xehaiky" class="example.com.XeMay">
<constructor-arg name="dongco" ref="dongcohaiky"></constructor-arg>
</bean>

<bean id="xebonky" class="example.com.XeMay">
<constructor-arg ref="dongcobonky"></constructor-arg>
</bean>
</beans>
Bây giờ mình sẻ phân tích ví dụ này.

Trước hết chúng ta hảy xem hàm main trong class App


public static void main(String[] args){

ApplicationContext context = 
new ClassPathXmlApplicationContext("beans.xml");

XeMay xehaiky = (XeMay) context.getBean("xebonky");
XeMay xebonky = (XeMay) context.getBean("xehaiky");

System.out.println(xehaiky.XeNoMay());
System.out.println(xebonky.XeNoMay());
}

Đáng ra nếu bình thường thì chúng ta thường viết như sau :


public static void main2(String[] args){

DongCo dongcohaiky = new DongCoHaiKy();
DongCo dongcobonky = new DongCoBonKy();

XeMay xehaiky = new XeMay(dongcohaiky);
XeMay xebonky = new XeMay(dongcobonky);

System.out.println(xehaiky.XeNoMay());
System.out.println(xebonky.XeNoMay());

}

So sánh ta có thể thấy ở đây trong hàm main chúng ta không cần dùng toán tử new để khởi tạo các đối tượng xehaiky và xebonky. Chúng ta củng không phải tạo các đối tượng động cơ để truyền vào cho các đối tượng của class XeMay. Vậy thì
- ai đả tạo ra các đối tượng xehaiky, xebonky?
- Và chúng lấy các đối tượng DongCo từ đâu ?
- Và file beans.xml có ý nghĩa và vai trò như thế nào?
Trước khi trả lời nhửng câu hỏi này mình muốn nhắc lại ở phần giới thiệu về IoC và DI mình đả nói là dùng IoC để thay đổi trách nhiệm tạo ra đối tượng “dongco” của class XeMay cho một thành phần nào đó bên ngoài. Trong bài helloworld này thành phần bên ngoài đả tạo ra các đối tượng xemayhaiky, xemaybonky và các đối tượng DongCo là các thành phần của spring framework mà chúng ta đả sử dụng(đó là IoC container).

Trong Spring các đối tượng chính để xây dựng ứng dụng thì được quản lý bởi Spring IoC container. Và IoC container gọi các đối tượng đó là các bean. Một bean chỉ đơn giản là một đối tượng được khởi tạo và quản lý bởi Spring IoC container.

Ta đả biết là giữa các bean thì có sự phụ thuộc lẩn nhau vậy làm sao Spring Framework biết được chúng phụ thuộc lẩn nhau như thế nào ? Làm sao biết được cần tạo ra đối tượng nào, truyền các loại DongCo vào các đối tượng của class XeMay ra sao , … Spring sử dụng hai cách( hai loại metadata) để người lập trình có thể cấu hình các bean (tạo ra như thế nào, phụ thuộc vào ai , …) đó là dùng Annotation( Java 5 mới hổ trợ Annotation) và file XML .
Trong ví dụ này mình đả sử dụng file beans.xml để cấu hình các bean. Trước khi phân tích file beans.xml nếu bạn nào chưa biết về xml thì có thể tham khảo tại đây :
[Only registered and activated users can see links. ]
File 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.xsd">

<bean id="dongcohaiky" class="example.com.DongCoHaiKy"></bean>
<bean id="dongcobonky" class="example.com.DongCoBonKy"></bean>

<bean id="xehaiky" class="example.com.XeMay">
<constructor-arg name="dongco" ref="dongcohaiky"></constructor-arg>
</bean>

<bean id="xebonky" class="example.com.XeMay">
<constructor-arg ref="dongcobonky"></constructor-arg>
</bean>
</beans>

Trước hết là phần tử beans đây là phần tử root của file xml. Nó sẽ chứa tất cả các phần tử bean của chúng ta và ngoài ra nó còn có một số thuộc tính nhưng trong khuôn khổ bài này mình nghĩ rằng chúng ta không phải quan tâm đến chúng.
Bây giờ chúng ta sẽ xét tới phần tử bean.



<bean id="dongcohaiky" class="example.com.DongCoHaiKy"></bean>

Với phần tử bean này chúng ta sẽ cấu hình cho IoC container tạo ra một bean của class "example.com.DongCoHaiKy". Ta thấy phần tử này có hai thuộc tính “id” và “class”. Thuộc tính “id” được dùng để định danh. Một bean có thể có nhiều id, nhưng các id không được trùng nhau.Còn thuộc tính “class” là dùng để chỉ bean đó được tạo thành từ class nào.
Nhưng với phần tử bean này nó lại có phần tử con :


<bean id="xehaiky" class="example.com.XeMay"> <constructor-arg name="dongco" ref="dongcohaiky"></constructor-arg> </bean>

Trong ví dụ mình đả đưa ra thì constructor của class XeMay có một đối số truyền vào. Và phần tử con <constructor-arg> dùng để cấu hình cho IoC container biết là phải truyền đối số nào vào cho constructer của class XeMay. Ta thấy phần tử <constructor-arg > có thuộc tính “ref = “dongcohaiky” ” cấu hình cho IoC container biết được là truyền bean nào vào cho contructer của class XeMay. Giá trị của thuộc tính ref là id của bean mà chúng ta muốn truyền vào.
Bây giờ chúng ta hảy xem lại hàm main, dòng đầu tiên là :


ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

Dòng này dùng để khởi tạo IoC container với phần cấu hình là file beans.xml. Và đối tượng context là đại diện cho container đó, nó có trách nhiệm khởi tạo, cấu hình các đối tượng và quản lý sự phuc thuộc giữa các đối tượng trong container.

Bạn có thể hình dung IoC container theo hình trên.


XeMay xehaiky = (XeMay) context.getBean("xebonky");

Ở đây ta dùng phương thức “getBean()” của ApplicationContext interface để truy cập bean có id =”xebonky” mà chúng ta đả cấu hình trong file beans. xml.
Để cấu hình các bean thì bạn sẻ phải sử dụng phần tử <bean></bean> trong file xml. Với phần tử này thì các bạn sẻ làm việc với các vấn đề sau :
• Namimg beans.
• Instantiating beans.
• Bean scopes.
• Dependency injection
• Autowiring collaboratiors.
• Lazy-initialized beans.
• Initialization callbacks.
• Destruction callbacks.

Chúng ta sẽ từng bước làm việc với các vấn đề này.

Naming beans:

Để beans container có thể quản lý được các bean thì chúng phải có cá định danh (giống như con người phải có tên vậy). Spring cho phép chúng ta có thể đặt cho bean một định danh hoặc có thể là nhiều định danh. Chúng ta cấu hình trên file xml thì chúng ta có thể dùng hai thuộc tính là “id “ và “name” để đặt định danh cho bean. Nếu chúng ta sử dụng id thì nó phải là duy nhất trong trong bean container. Khi bạn muốn nhiều định danh cho một bean bạn có thể dùng thuộc tính name và các định danh với name có thể cách nhau bằng khoảng trắng, dấu phẩy hoặc dấu chấm phẩy. Nếu bạn không tự định danh cho bean thì bean container sẻ tự sinh ra cho bean đó một định danh.
Với hai cách định danh trên thì các thuộc tính thuộc phần tử <bean>. Bạn có thể thêm định danh cho bean bằng cách dùng alias. Bạn có thể dùng phần tử <alias> để thêm định danh cho bean. Để dễ hiểu hơn bây giờ mình sẻ lấy một ví dụ về định danh cho bean:


File: context.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.xsd">

<bean id="name1" name="name2,name3,name4" class="java.lang.String"/>
<alias name="name1" alias="namex1"/>
<alias name="name1" alias="namex2"/>

</beans>


using

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class Main {
public static void main(String[] a) {
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("context.xml"));

String s1 = (String) factory.getBean("name1");
String s2 = (String) factory.getBean("name2");
String s3 = (String) factory.getBean("name3");
String s4 = (String) factory.getBean("name4");
String s5 = (String) factory.getBean("namex1");
String s6 = (String) factory.getBean("namex2");

System.out.println((s1 == s2));
System.out.println((s2 == s3));
System.out.println((s3 == s4));
System.out.println((s4 == s5));
System.out.println((s5 == s6));
}
}

Khi container tạo một bean thì làm sao nó biết được là cần tạo bean của class nào. Với XML thì chúng ta sử dụng thuộc tính “class” trong phần tử <bean>.
Như chúng ta đả biết trong lập trình java có hai cách để chúng ta tạo ra đối tượng. Cách thứ nhất là dùng toán tử new ( thông qua constructor). Cách thứ hai là dùng hàm static của một class nào đó(thường là một Factory). Ví dụ như :

XeMay xemay = new XeMay(); // qua constructor
XeMay xemay = HonDa.createXeMay(); //qua static method là createXeMay().

Và spring củng hổ trợ chúng ta hai cách để tạo ra bean bằng constructor và static method.

Khởi tạo bằng constructor:

bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
Như ví dụ thì thuộc tính class được gán bằng tên của class mà nó muốn tạo bean.
Khởi tạo bằng static method :

Giả sử ta có class sau :
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}

để khởi tạo đối tượng cho class đó thì ta phải cấu hình như sau :

<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
Khi đó thuộc tính class sẻ được gán bằng tên của Class có phương thức static như ví dụ trên.
Nhưng khi mà khởi tạo một đối tượng (bean) từ một đối tượng (bean) khác thì sao. Spring làm như ví dụ sau :
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private DefaultServiceLocator() {}
public ClientService createClientServiceInstance() {
return clientService;
}
}

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService" factory-bean="serviceLocator" factory-method = "createClientServiceInstance"/>
bean scope.

Khi bạn cấu hình một bean, và bean container sẻ tạo đối tượng(bean) cho bạn.Bạn sẻ muốn bean container tạo cho bạn mấy đối tượng như vậy, hay là chỉ cần tạo một đối tượng thôi thôi ,… Và để cấu hình việc này bạn phải sử dụng thuộc tính scope. Scope sẻ có nhửng giá trị sau :

Singleton : Với mổi bean container chỉ tao duy nhất một đối tượng
Prototype: tạo một đối tượng mới khi có yêu cầu
Request : tạo một đối tượng cho mổi lần có HTTP request.
Session : tạo một đối tượng cho mổi HTTP session.
globalSession : tạo một đối tượng cho một global HTTP session.

Trong phạm vi bài này mình chỉ muốn giới thiệu đến Singleton và Prototype. Vì đây là hai giá trị thường được dùng nhât. Còn ba thuộc tính còn lại chỉ sử dụng trong ứng dụng web. Và giá trị mặc định của scope là singleton.
Scope = “singleton” nghỉa là trong một bean container chỉ tạo ra một đối tượng duy nhất của bean đó. Để dễ hiểu chúng ta lấy ví dụ như sau :
File CustomerService.java
package com.example;

public class CustomerService 
{
String message;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}

File cấu hình beans.xml:
<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.5.xsd">

<bean id="customerService" 
class="com.example.CustomerService" scope="singleton" />

</beans>

File App.java

package com.example;

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

import com.example.CustomerService;

public class App 
{
public static void main( String[] args )
{
ApplicationContext context = 
new ClassPathXmlApplicationContext(new String[] {"beans.xml"});

CustomerService custA = (CustomerService)context.getBean("customerService");
custA.setMessage("Message by custA");
System.out.println("Message : " + custA.getMessage());

CustomerService custB = (CustomerService)context.getBean("customerService");
System.out.println("Message : " + custB.getMessage());
}
}

Khi chúng ta chạy ứng dụng này thì kết quả thu được sẻ là :

Message : Message by custA
Message : Message by custA

Như bạn có thể thấy ở đây khi chúng ta yều cầu bean container hai lần nhưng chỉ có một đối tượng được tạo ra.

Còn với scope=”prototype” thì mổi lần chúng ta yêu cầu bean container sẻ tạo cho chúng ta một đối tượng mới. Và với ví dụ trên nếu chúng ta thay đổi scope = “prototype” như sau :

No comments:

Post a Comment