You are on page 1of 22

Phần 1: Spring IoC , Inversion of Control trong Spring

1. IoC là gì?
IoC(Inversion of Control): Đảo ngược điều khiển, nó giúp làm thay đổi
luồng điều khiển của chương trình một cách linh hoạt.
Thường dùng với Denpendency Injection.

2. Spring IoC

IoC Container là thành phần thực hiện IoC.

Trong Spring, Spring Container (IoC Container) sẽ tạo các đối tượng, lắp rắp chúng lại với nhau, cấu hình
các đối tượng và quản lý vòng đời của chúng từ lúc tạo ra cho đến lúc bị hủy.

Spring container sử dụng DI để quản lý các thành phần, đối tượng để tạo nên 1 ứng dụng. Các thành
phần, đối tượng này gọi là Spring Bean (mình sẽ nói về Spring Bean trong các bài sau)

Để tạo đối tượng, cấu hình, lắp rắp chúng, Spring Container sẽ đ ọc thông
tin từ các file xml và thực thi chúng.

IoC Container trong Spring có 2 kiểu là:


 BeanFactory
 ApplicationContext
Sự khác nhau giữa BeanFactory và
ApplicationContext:
BeanFactory và ApplicationContext đều là các interface th ực hi ện IoC
Container. ApplicationContext được xây dựng BeanFactory nh ưng nó
có thêm một số chức năng mở rộng như tích hợp v ới Spring AOP, x ử lý
message, context cho web application.

3. Ví dụ với BeanFactory và
ApplicationContext.
3.1 BeanFactory
Để sử dụng Spring Bean ta cần khai báo thư viện spring-bean sau:

 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>4.3.13.RELEASE</version>
 </dependency>
Class HelloWorld.java

 public class HelloWorld {


 private String message;

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

 public void getMessage() {
 System.out.println("Print : " + message);
 }
 }
Để tạo đối tượng HelloWorld thông qua IoC container ta s ẽ c ấu hình nó
trong 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-3.0.xsd">

 <bean id = "helloWorld" class = "stackjava.com.springioc.beanfactory.HelloWorld"
>
 <property name = "message" value = "Hello World!"/>
 </bean>

 </beans>
beans.xml là 1 file Spring Bean Configuration, nó có s ẵn m ột s ố khai
báo namespace trong tempalte, bạn có thể tạo 1 file xml rồi copy d ữ
liệu ở trên vào hoặc tạo file này bằng Spring Tool:
Phần 2: Spring Bean, Các scope trong Spring, Spring Bean Scope
Bây giờ ta sẽ tạo một BeanFactory để đọc các thông tin c ấu hình và t ạo
ra đối tượng HelloWorl.

BeanFactory chỉ là 1 interface, nên ở đây mình


dùng DefaultListableBeanFactory, một implement của BeanFactory. Ở
các version cũ thì bạn sẽ thấy hay sử dụng XmlBeanFactory nh ưng nó b ị
đánh dấu @Deprecated ở các version mới.

 // tạo factory
 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

 // đọc thông tin file cấu hình và gán vào factory
 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
 reader.loadBeanDefinitions(new ClassPathResource("beans.xml"));

 //tạo đối tượng từ factory
 HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
 obj.getMessage();
Kết quả:

Print : Hello World!

3.2 Application Context


Để sử dụng Spring Bean ta cần khai báo thư viện spring-context sau:

 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>4.3.13.RELEASE</version>
 </dependency>
Mình sẽ tạo đối tượng phức tạp hơn HelloWorl.java một chút.

Ví dụ class DataResource.java chứa thông tin kết nối tới database.

 public class DataResource {


 private String driverClassName;
 private String url;
 private String username;
 private String password;

 public String getDriverClassName() {
 return driverClassName;
 }

 public void setDriverClassName(String driverClassName) {
 this.driverClassName = driverClassName;
 }

 public String getUrl() {
 return url;
 }

 public void setUrl(String url) {
 this.url = url;
 }

 public String getUsername() {
 return username;
 }

 public void setUsername(String username) {
 this.username = username;
 }

 public String getPassword() {
 return password;
 }

 public void setPassword(String password) {
 this.password = password;
 }

 public void printConnection() {
 System.out.println("url: " + this.url + "\n" + "username/password: " +
this.username + "/" + this.password);
 }
 }
Để tạo đối tượng HelloWorld thông qua IoC container ta s ẽ c ấu hình nó
trong file applicationContext.xml (lưu ý là bạn đ ặt tên file là gì c ũng
được: bean.xml, applicationContext.xml, dataresource.xml… nh ưng c ần
phải nhớ file cấu hình cho cái gì)

 <?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="dataResource"
class="stackjava.com.springioc.applicationcontext.DataResource">
 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
 <property name="url" value="jdbc:mysql://localhost/database_name" />
 <property name="username" value="root" />
 <property name="password" value="admin1234" />
 </bean>

 </beans>

Tạo một đối tượng ApplicationContext để lấy thông tin từ file c ấu hình
và tạo đối tượng DataResource

 public static void main(String[] args) {


 ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
 DataResource obj = (DataResource) context.getBean("dataResource");
 obj.printConnection();
 }
Kết quả:

url: jdbc:mysql://localhost/database_name

username/password: root/admin1234

Khi nhắc tới Scope trong Spring người ta thường nói t ới Bean Scope
(Scope của các bean trong Spring).
Nó khác với scope trong JSP-Servlet mà tương tự bean scope trong JSF

1. Spring Bean là gì?


Spring Bean là các object trong Spring Framework, đ ược kh ởi t ạo
thông qua Spring Container. Bất kỳ class Java POJO nào c ũng có th ể là
Spring Bean nếu nó được cấu hình và khởi tạo thông qua container b ằng
việc cung cấp các thông tin cấu hình (các file config .xml, .properties..)

2. Các Bean Scope trong Spring


Có 5 scope được định nghĩa cho Spring Bean:

Singleton: Chỉ duy nhất một thể hiện của bean sẽ được tạo cho mỗi container. Đây là
scope mặc định cho spring bean. Khi sử dụng scope này cần chắc chắn rằng các bean
không có các biến/thuộc tính được share.
 Prototype: Một thể hiện của bean sẽ được tạo cho mỗi lần được yêu cầu(request)
 Request: giống với prototype scope, tuy nhiên nó dùng cho ứng dụng web, một thể hiện
của bean sẽ được tạo cho mỗi HTTP request.
 Session: Mỗi thể hiện của bean sẽ được tạo cho mỗi HTTP Session
 Global-Session: Được sử dụng để tạo global sesion bean cho các ứng dụng Portlet.
Trong 5 scope trên thì 3 scope cuối chỉ dùng trong ứng dụng web.
Bạn cũng có thể tự định nghĩa các scope cho riêng mình, tuy nhiên các
scope cung cấp bởi spring dùng tốt và đáp ứng hầu hết các trường hợp.

Để thay đổi Scope của các bean bạn có thể định ngh ĩa nó trong file xml,
hoặc các annotation:

hoặc

2. Denpendency Injection trong


Spring
Bạn có thể dễ dàng thực hiện Dependency Injection b ằng cách t ự code,
tự định nghĩa các điều kiện tạo thể hiện… Tuy nhiên trong th ực t ế ng ười
ta thường dùng các thư viện, framework để thực hiện Dependency
Injection một cách thuật tiện, dễ hiểu hơn.

Ví dụ sử dụng thư viện CDI, các framework như Spring, JSF c ũng đ ều h ỗ
trợ Denpendency Injection.

Trong Spring có 2 cách thực hiện Injection Dependency là: qua hàm
khởi tạo và qua hàm setter (By Constructor / By Setter method)

Code ví dụ:

 <?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="helloWorld1" class="stackjava.com.springdi.demo.HelloWorld">
 <property name="message" value="inject by setter" />
 </bean>

 <bean id="helloWorld2" class="stackjava.com.springdi.demo.HelloWorld">
 <constructor-arg value="inject by constructor" type="String"></constructor-arg>
 </bean>

 </beans>
 public class HelloWorld {
 private String message;

 public HelloWorld() {
 }

 public HelloWorld(String message) {
 this.message = message;
 }

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

 public String getMessage() {
 return message;
 }

 public void print() {
 System.out.println("Print: " + this.message);
 }
 }
 public class MainApp {
 public static void main(String[] args) {
 ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
 HelloWorld helloWorld1 = (HelloWorld) context.getBean("helloWorld1");
 helloWorld1.print();
 HelloWorld helloWorld2 = (HelloWorld) context.getBean("helloWorld2");
 helloWorld2.print();

 }
 }
Kết quả:

Print: inject by setter

Print: inject by constructor

3. Sự khác nhau giữa CI (Injection by


Constructor) với SI (Injection by
Setter)
Inject từng phần: bạn có thể inject từng thuộc tính bằng setter injection nhưng không thể
làm với constructor.
 Overriding: Setter injection ghi đè lại constructor injection, nếu ta dùng cả constructor và
setter injection, IoC container sẽ sử dụng setter injection
 Chuyển đổi: Ta có thể dễ dàng thay đổi giá trị bằng setter injection mà ko cần tạo một thể
hiện mới của bean.
(Lưu ý: nếu sử dụng setter injection thì class của bạn phải có hàm kh ởi
tạo mặc định không tham số, nếu dùng constructor injection thì ph ải có
hàm khởi tạo với các tham số tương ứng với injection).

Spring Core – Phần 4: Spring Dependency Injection v ới Object,


Collections, Map

1. Spring DI với Object (Dependent


Object)
Trường hợp mối quan hệ giữa các class là has-a (1 đối t ượng ch ứa 1 đ ối
tượng khác) chúng ta sẽ tạo bean cho đối tượng bên trong và truy ền nó
vào hàm khởi tạo hoặc setter.
Ví dụ dưới đây là trường hợp Person has-a Address (một person có m ột
address bên trong):

 public class Address {


 private String country;
 private String province;
 private String district;

 public Address() {
 }

 public Address(String country, String province, String district) {
 this.country = country;
 this.province = province;
 this.district = district;
 }

 public String getCountry() {
 return country;
 }

 public void setCountry(String country) {
 this.country = country;
 }

 public String getProvince() {
 return province;
 }

 public void setProvince(String province) {
 this.province = province;
 }

 public String getDistrict() {
 return district;
 }

 public void setDistrict(String district) {
 this.district = district;
 }

 @Override
 public String toString() {
 return "Address [country=" + country + ", province=" + province + ", district=" +
district + "]";
 }

 }
 public class Person {
 private String name;
 private int age;
 private Address address;

 public Person() {
 }

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

 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;
 }

 public int getAge() {
 return age;
 }

 public void setAge(int age) {
 this.age = age;
 }

 public void print() {
 System.out.println("Person: " + this.name + " Age: " + this.age + " Address: " +
this.address.toString());
 }

 }
Trong file cấu hình ta sẽ tạo bean cho đối tượng Address và truyền nó
vào bean của đối tượng Person:

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">

 <!-- Inject by setter -->
 <bean id="person" class="stackjava.com.springdiobject.demo.Person">
 <property name="name" value="stackjava.com"></property>
 <property name="age" value="25"></property>
 <property name="address" ref="address"></property>
 </bean>

 <!-- Inject by constructor -->
 <bean id="person2" class="stackjava.com.springdiobject.demo.Person">
 <constructor-arg name="name" type="String" value="spring"></constructor-arg>
 <constructor-arg name="age" type="int" value="30"></constructor-arg>
 <constructor-arg name="address" ref="address"></constructor-arg>
 </bean>

 <bean id="address" class="stackjava.com.springdiobject.demo.Address">
 <property name="country" value="Viet Nam"></property>
 <property name="province" value="Ha Noi"></property>
 <property name="district" value="Thanh Xuan"></property>
 </bean>

 </beans>
Demo:

 public class MainApp {


 public static void main(String[] args) {
 ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
 Person person= (Person) context.getBean("person");
 person.print();

 Person person1 = (Person) context.getBean("person2");
 person1.print();

 }
 }
Kết quả:

Person: stackjava.com Age: 25 Address: Address [country=Viet Nam, province=Ha Noi, district=Thanh Xuan]

Person: spring Age: 30 Address: Address [country=Viet Nam, province=Ha Noi, district=Thanh Xuan]

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

2. Spring DI với Collections


(Dependent Collections)
Tương tự ví dụ trên nhưng đối tượng Person có nhiều Address, nhiều
email:

 public class Person {


 private String name;
 private int age;
 private List<Address> addresses;
 private List<String> emails;

 public Person() {
 }

 public Person(String name, int age, List<Address> addresses, List<String> emails)
{
 this.name = name;
 this.age = age;
 this.addresses = addresses;
 this.emails = emails;
 }

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public int getAge() {
 return age;
 }

 public void setAge(int age) {
 this.age = age;
 }

 public List<Address> getAddresses() {
 return addresses;
 }

 public void setAddresses(List<Address> addresses) {
 this.addresses = addresses;
 }

 public List<String> getEmails() {
 return emails;
 }

 public void setEmails(List<String> emails) {
 this.emails = emails;
 }

 public void print() {
 System.out.println("Person: " + this.name + " Age: " + this.age);
 System.out.println("Address: ");
 for (Address address : addresses) {
 System.out.println(address);
 }
 System.out.println("Email:");
 for (String email : emails) {
 System.out.println(email);
 }
 System.out.println("++++++++++++++++++++++++++++++++++");
 }

 }
File cấu hình 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">


 <!-- Inject by constructor -->
 <bean id="person2" class="stackjava.com.springdicollections.demo.Person">
 <constructor-arg name="name" type="String" value="spring"></constructor-arg>
 <constructor-arg name="age" type="int" value="30"></constructor-arg>
 <constructor-arg name="addresses">
 <list>
 <ref bean="address1" />
 <ref bean="address2" />
 </list>
 </constructor-arg>
 <constructor-arg name="emails">
 <list>
 <value>abc@gmail.com</value>
 <value>def@yahoo.com</value>
 </list>
 </constructor-arg>
 </bean>

 <!-- Inject by setter -->
 <bean id="person" class="stackjava.com.springdicollections.demo.Person">
 <property name="name" value="stackjava.com"></property>
 <property name="age" value="25"></property>
 <property name="addresses">
 <list>
 <ref bean="address2" />
 </list>
 </property>
 <property name="emails">
 <list>
 <value>ghi@hotmail.com</value>
 <value>klm@zzz.com</value>
 </list>
 </property>

 </bean>

 <bean id="address1" class="stackjava.com.springdicollections.demo.Address">
 <property name="country" value="Viet Nam"></property>
 <property name="province" value="Ha Noi"></property>
 <property name="district" value="Thanh Xuan"></property>
 </bean>
 <bean id="address2" class="stackjava.com.springdicollections.demo.Address">
 <property name="country" value="Viet Nam"></property>
 <property name="province" value="Ha Noi"></property>
 <property name="district" value="Ha Dong"></property>
 </bean>

 </beans>
Demo:

 public static void main(String[] args) {


 ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
 Person person = (Person) context.getBean("person");
 person.print();

 Person person1 = (Person) context.getBean("person2");
 person1.print();

 }
Kết quả:

Person: stackjava.com Age: 25

Address:

Address [country=Viet Nam, province=Ha Noi, district=Ha Dong]

Email:
ghi@hotmail.com

klm@zzz.com

++++++++++++++++++++++++++++++++++

Person: spring Age: 30

Address:

Address [country=Viet Nam, province=Ha Noi, district=Thanh Xuan]

Address [country=Viet Nam, province=Ha Noi, district=Ha Dong]

Email:

abc@gmail.com

def@yahoo.com

++++++++++++++++++++++++++++++++++

Các trường hợp dùng với Set, Map tương tự như List.

You might also like