Chưa phân loại, Java

MDB != JMS and vice-versa


  • A Message Driven Bean (further referred to as MDB) is just another EJB like Stateless, Stateful or a Singleton. It’s specified using the @MessageDriven annotation.
  • MDBs are used for asynchronous message processing
  • They are similar to Stateless EJBs since both of them are pooled by the EJB container
  • However they differ from Stateless EJBs since MDBs cannot be directly accessed by a client. Only the container calls them in response to a message sent by the client to an endpoint which the MDB is listening to.

Commonly used pattern for MDB

  • MDBs are generally used along with JMS (Java Message Service API)
  • A MDB is configured to listen to a JMS destination using @ActivationConfigProperty, implements the javax.jms.MessageListener interface and provides the business logic (message processing) in the onMessage method
  • A component sends a Message to the JMS destination (end point). This is not a synchronous process (as already mentioned above). The message firing method returns immediately and the container takes care of calling the MDB configured to listen that particular JMS destination

JMS based MDB

MDB myth

  • MDBs are not part of the JMS spec or coupled with JMS by any means – this is a misconception.
  • MDB are pooled beans which can process messages in an async fashion and can listen to any end point including a JMS queue or destination (most generally seen).
  • In fact, this has been the case since EJB 2.1 and is made possible by the JCA (Java Connector Architecture) spec

What’s JCA ?

  • On a high level, JCA enables Java EE servers to interact with external systems e.g. legacy enterprise information sources etc via a standard SPI (not dealing with intricate JCA details here)
  • One can use the JCA standard interfaces to build a Resource Adapter (RAR file) for a specific system
  • JCA provides contracts for two-way communication (inbound and outbound) b/w the Java EE container and the external system – the implementation for which needs to be present withing the Resource Adapter itself

 Courtesy: JCA Specification document

How does JCA enable the concept of Generic MDBs ?

  • JCA defines MDB specific features
  • Just like in the case of a JMS based MDB, a JCA based MDB also needs to implement an interface and define activation properties (both are specific to the JCA Resource Adapter implementation)
  • The external system sends a message which the Resource Adapter accepts via its implementation of the inbound JCA contract and this message is relayed to an internal endpoint (this is again specific to the JCA adapter implementation)
  • The MDB registered to this endpoint kicks in an executes the business logic on the received message

JCA based MDB

End result

An external system sending messages to a Java EE container using a standard interface (JCA) while the JCA implementation takes care of delivering it to the appropriate endpoint which further delivers it to the registered MDB

Thing to notice is that this is completely portable across Java EE servers since, EJB spec vendors have to support JCA based MDBs.


How to use CodePro AnalytiX to develop Automated Unit testing

Sometimes, we need to develop Automated Unit testing for a complicated logic or some utility functions that we can not execute directly from our application. For example, we and client are developing a interesting module at the same time, we need to create some stubs or drivers or mock objects for our logic can be executed. How do we do that?

There are many ways to do that, but mainly are: manual testing and automated testing.

Manual testing:

Write stubs or drivers that we need
Write a “main” function to test for our logic.
Execute environment set-up code…

Automated testing:

Write @Test function
Do not need stubs or drivers
Use mocking technique to create mock objects. Very simple and quickly

Advantaged of automated testing over manual testing:

Save time.

How about the disadvantaged:

We need to learn how to write automated testing

OK. Let’s get started with CodePro AnalytiX – an Automated testing tool by setting up that tool in Eclipse, and playing around with some “real-world” code:


Required: Eclipse 3.4+
Go to this site and find the update link corresponding to your Eclipse version.

Here I use Eclipse 3.7 (Indigo)

Note: Google was not published any new version since 3.7. So if you are using an Eclipse version that is greater than 3.7, please use …

Go to Eclipse menu Help –> Install New Softwares…


Enter the CodePro AnalytiX update link into “Work with:” text box. Select CodePro item and install it by clicking Next, accept the term of use, then Finish. You might need to restart the Eclipse after installation to to take effect.

Using CodePro AnalytiX

It’s very easy to start using CodePro AnalytiX.

Assume we have a project called “MyBusiness“.

A class with name “Range“. Does it make sense with Project objective. NO!!!

package com.mycomp.product;
    public class Range {
    private double begin;
    private double end;
    Range(double begin, double end) {
        if(end < begin) {             throw new IllegalArgumentException("inLength must be larger or equals 0");         }         this.begin = begin;         this.end = end;     }     boolean isIntersect(Range inOtherRange) {         return end > inOtherRange.begin && begin < inOtherRange.end;
    boolean isInclude(Range inOtherRange) {
        return begin <= inOtherRange.begin && end >= inOtherRange.end;
    public String toString() {
    return String.format("[%f, %f]", begin, end);

Now, right-click on class that you want to generate the test case as well as test class and test project if it not exist, then select: CodePro Tools –> Generate Test Cases

CodePro Tools will do his job right away. You can see a new project “MyBusinessTest” is generated.

Structure of Test project:


There is class RangeTest. It is test class for Range.

RangeTest is also put in the package com.mycomp.product. That means, test code is able to access to the production code with package level accessing. It’s very nice and also is the best practice for Test project structure.

For each level of package, we have a TestAll class. If we want to run all test classes inside the package com.mycomp.product, run the class com.mycomp.product.TestAll. Run class com.mycomp.TestAll to execute whole test classes in project.

Look inside the test class, CodePro AnalytiX has generated some test method. But it seems not benefit for us, so just simply delete it except main method.setUp and tearDown are also need in case you need some configuration before and after executing any test case.

OK, now let add some test case from scratch, by typing:

public void testName() throws Exception {

Go ahead and write some amazing test.

Run the test:

Right-click on test class or TestAll class and choose: Run As –> JUnit Test (Shortcut key are the best choice when running test)

Design Pattern, OO Design Principles, Tản mạn

Tản mạn về Dependency Injection

Tản mạn về Dependency Injection

Như thường lệ, blog của mình sẽ rất ít các định nghĩa, rất nhiều code, hình ảnh minh họa và những câu nói dí dỏm. OK, hãy bắt đầu với định nghĩa về Dependency


Khi trong class A có sự tồn tại của lớp B, dùng lớp B để làm 1 công việc gì đó, ta nói lớp A đang phụ thuộc vào lớp B. Ví dụ:

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public class CustomerRepository {
	public Customer findOne(String customerId) {
		// Code stuff

	public Collection<Customer> findAll() {
		// Code stuff

	public void create(Customer customer) {
		// Code stuff

	public boolean update(Customer customer) {
		// Code stuff

	public void delete(Customer customer) {
		// Code stuff

package com.edward.tutorial.di.service;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;
import com.edward.tutorial.di.repository.CustomerRepository;

public class CustomerService {
	CustomerRepository customerRepository;
	Collection<Customer> findAll() {
		return customerRepository.findAll();

	Customer create(Customer customer) {
		return customer;
	Customer update(Customer customer) {
		return customer;

	void delete(String customerId) {
		Customer customer = findOne(customerId);
	public Customer findOne(String customerId) {
		return customerRepository.findOne(customerId);

Như ví dụ ở trên, lớp CustomerService đang phụ thuộc vào lớp CustomerRepository, vì CustomerService đang sử dụng 1 instance của CustomerRepository để thực hiện việc lưu trữ dữ liệu xuống database, cụ thể ở đây là customerRepository. Dependency1 Vậy: customerRepository được khởi tạo ở đâu? Vì nếu không được khởi tạo, thì khi sử dụng chúng ta sẽ nhận được NullPointerException. Câu trả lời là: để sử dụng được đối tượng customerRepository trong CustomerService, chúng ta sẽ có 2 cách:

  1. Khởi tạo đối tượng customerRepository trong lớp CustomerService.
  2. Truyền (Inject) đối tượng customerRepository đã được khởi tạo sẵn từ bên ngoài vào lớp CustomerService.



CHÚNG TA VỪA NHẮC ĐẾN INJECT. ĐÚNG VẬY, KHI LÀM THEO CÁCH 2, NGHĨA LÀ CHÚNG TA ĐANG THỰC HIỆN DEPENDENCY INJECTION. MỘT LƯU Ý KHÁC: Nếu chỉ muốn hiểu Dependency Injection là gì thì xin chúc mừng, chúng ta đã hoàn thành mục tiêu ở đây. Tuy nhiên chắc sẽ chẳng ai muốn dừng lại tại đây. Cho nên chúng ta sẽ đi tiếp phần demo và những chủ đề liên quan đến Dependency Injection Tiếp tục với việc demo cho 2 cách trên. Dependency3 Vậy các bạn sẽ tự hỏi: cách nào là tốt nhất, lúc nào nên dùng cách nào? Câu trả lời vẫn như mọi khi: không cách nào là hoàn hảo.

Tightly coupling và Loosely coupling

Trước khi đi vào phân tích ưu nhược của các cách làm, chúng ta cần làm rõ 2 khái niệm: tightly coupling và loosely coupling.

Tightly coupling:

Ở cách 1, khi khởi tạo đối tượng customerRepository ngay trong lớp CustomerService, ta nói lớp CustomerService đang phụ thuộc hoàn toàn vào lớp CustomerRepository. Trong suốt quá trình chương trình được thực thi (runtime), lớp CustomerService sẽ chỉ làm việc với duy nhất thể hiện của lớp CustomerRepository. Ở cách 2, mặc dù chúng ta không khởi tạo trực tiếp đối tượng customerRepository trong lớp CustomerService mà inject từ ngoài vào, nhưng lớp CustomerService vẫn chỉ làm việc được đối tượng customerRepository, do đó, cách 2 vẫn là Tightly coupling. Vậy, tightly coupling là việc một lớp TRỰC TIẾP sử dụng (phụ thuộc) trực tiếp vào thể hiện cụ thể của 1 lớp khác. TightlyCoupling

Loosely coupling:

Trái với tightly coupling, dễ dàng suy ra loosely coupling là việc một lớp KHÔNG TRỰC TIẾP sử dụng (phụ thuộc) vào thể hiện cụ thể của bất cứ 1 lớp cụ thể nào. Cho đến bây giờ vẫn chưa có 1 ví dụ nào để cho thấy loosely coupling như thế nào. Trong Java (hoặc các ngôn ngữ lập trình hướng đối tượng khác), để đạt được loosely coupling trong thiết kế, chúng ta cần sử dụng khái niệm “đa hình” (polymorphism). Tính đa hình trong lập trình hướng đối tượng là việc định nghĩa những đối tượng trừu tượng (abstraction) như abstract class hoặc interface. Những đối tượng abstraction này khai báo hoặc đưa ra quy ước (contract) và cho phép nhiều lớp đối tượng cụ thể kế thừa và định nghĩa lại hành vi cho riêng chúng.

Ví dụ về tính đa hình

Một tổ chức tiêu chuẩn ISO nào đó đưa ra định nghĩa về chiếc điện thoại: điện thoại là vật có khả năng nghe và nhận cuộc gọi. Lúc này ISO chưa hề cho ra đời 1 chiếc điện thoại nào có thể cầm nắm được, túm lại, nó chỉ là định nghĩa, để khi có người đang cầm trên tay 1 chiếc điện thoại thực sự thì họ có thể gọi hoặc nhận cuộc gọi. Sau khi đã có định nghĩa thế nào là điện thoại, các nhà sản xuất điện thoại hàng đầu thế giới mới bắt tay vào việc sản xuất ra những chiếc điện thoại theo tiêu chuẩn đã đặt ra bởi ISO. Hiện tại có 2 nhà sản xuất là Nokia và Samsung. Mục đích của họ là phải sản xuất ra những chiếc điện thoại có thể nghe và gọi được theo tiêu chuẩn ISO. Khi những chiếc điện thoại được tung ra thị trường, người sử dụng sau đó mua về và thực hiện chức năng nghe gọi mà họ đã từng được nghe ISO công bố trước đó. Tuy nhiên khi thực hiện cuộc gọi từ điện thoại Nokia thì sẽ nghe câu “Hello Microsoft” đầu tiên, còn với Samsung sẽ là câu “Lee Yong-dae” chẳng hạn. (I love Badminton). Có một nhà sản xuất nghiệp dư (giấu tên) cũng tập tành sản xuất điện thoại nhưng không tuân theo tiêu chuẩn của ISO, vậy nên khi cho ra thị trường, người ta không thể thực hiện nghe gọi, mà chỉ có thể… nghe nhạc. Vậy nên có thể gọi đây là cái máy nghe nhạc (tuân theo tiêu chuẩn của một tổ chức nào đó dành cho máy nghe nhạc), chứ không phải cái điện thoại. Phần mô tả cho đa hình đến đây là hết. Cười chút đã. =)) Do vậy, một lớp được gợi là loosely couling khi nó chỉ phụ thuộc vào các đối tượng high level (Abstract class hoặc Interface) thay vì phụ thuộc vào các lớp đối tượng cụ thể (concrete class). (Giống như việc một người tuyên bố, tui biết sử dụng tất cả điện thoại, miễn là nó có thể gọi và nghe, chứ không riêng gì cái điện thoại mà cứ phát ra câu “Lee Yong-dae”.) Ví dụ với bài Điện thoại theo chuẩn ISO ở trên


public abstract class Phone {
	public abstract void call(String number);
	public abstract void answer(String number);


public class NokiaPhone extends Phone {

	public void call(String number) {
		System.out.println("Microsoft... " + number);

	public void answer(String number) {
		System.out.println(number + " Buy me...");


public class SamsungPhone extends Phone {

	public void call(String number) {
		System.out.println("Kpop Kpop Kpop... " + number);

	public void answer(String number) {
		System.out.println(number + " I wanna cry...");


public class User {
	Phone phone;
	public User(Phone phone) { = phone;
	public void bringMePhone(Phone phone) { = phone;
	public void call(String number) {;
	public void answer(String number) {


public class Main {

	public static void main(String[] args) {
		User bill = new User(new SamsungPhone());"0123");
		bill.bringMePhone(new NokiaPhone());

Quay lại ví dụ của chúng ta Extract CustomerRepository class thành CustomerRepository interface

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public interface CustomerRepository {

	public abstract Customer findOne(String customerId);

	public abstract Collection<Customer> findAll();

	public abstract void create(Customer customer);

	public abstract boolean update(Customer customer);

	public abstract void delete(Customer customer);


CustomerRepositoryImpl sẽ implement CustomerRepository interface

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public class CustomerRepositoryImpl implements CustomerRepository {
	public Customer findOne(String customerId) {
		// Code stuff

	public Collection<Customer> findAll() {
		// Code stuff

	public void create(Customer customer) {
		// Code stuff

	public boolean update(Customer customer) {
		// Code stuff

	public void delete(Customer customer) {
		// Code stuff

Và inject CustomerRepository interface thay vì CustomerRepositoryImpl

package com.edward.tutorial.di.service;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;
import com.edward.tutorial.di.repository.CustomerRepository;

public class CustomerService {
	CustomerRepository customerRepository;
	public CustomerService(CustomerRepository customerRepository) {
		this.customerRepository = customerRepository;
	Collection<Customer> findAll() {
		return customerRepository.findAll();

	Customer create(Customer customer) {
		return customer;
	Customer update(Customer customer) {
		return customer;

	void delete(String customerId) {
		Customer customer = findOne(customerId);
	public Customer findOne(String customerId) {
		return customerRepository.findOne(customerId);


Nên design theo Tightly coupling hay Loosely coupling

Câu trả lời là Loosely coupling. Vì sao? Đọc tiếp…

Loosely coupling = Dependency Injection + Abstraction

Dependency Injection không giúp chúng ta cải thiện tính flexibility trong thiết kế. Tuy nhiên khi chúng ta kết hợp với Abstraction bằng cách inject các đối tượng abtract, thì chúng ta đã có một bản thiết kế loosely coupling và flexibility.

Dependency inversion principle

Dependency inversion principle là 1 trong 5 nguyên lý thiết kế hướng đối tượng (S.O.L.I.D). Xem thêm tại ( Nói đơn giản, Dependency inversion principle giúp chúng ta có được 1 thiết kế loosely coupling Dependency inversion principle = Loosely coupling = Dependency Injection + Abstraction

Inversion of Control (IoC)

Nếu như Dependency inversion là principle thì Inversion of Control là pattern tuân theo principle này. Trong Java, IoC pattern xuất hiện khá nhiều. Lấy 1 ví dụ rất quen thuộc, đó là hàm public static void main(String[] args)

package com.edward.tutorial.di;

public class Main {

    public static void main(String[] args) {
        System.out.println("Developer's dream starts from here");

    private static void doMyWish() {
        System.out.println("I wish this app would be the most favourite one in the world");

Tất cả các lập trình viên Java đều quá quen thuộc với hàm main này – entry point của 1 chương trình Java truyền thống. Lần này chúng ta sẽ không bàn đến cú pháp, mà bàn đến một việc mà được cho là “chẳng ai quan tâm là mấy”. Câu hỏi là: hàm doMyWish() được gọi bởi hàm main(), vậy hàm main() được gọi bởi hàm nào? Câu trả lời là: Java sẽ gọi hàm main() của chúng ta. Vậy làm thế nào mà Java (chính xác hơn là javac.exe hay đại loại là một cái cao siêu gì đó) có thể gọi được hàm main của chúng ta?

Hollywood principle: “Don’t call us, we’ll call you.”

Dịch nôm na: “Đừng có gọi cho tui, để lại số điện thoại, tui sẽ gọi bạn.” Ngôi sao mà, có quyền chảnh. Nếu nói Java là 1 ngôi sao Hollywood, và hàm main là 1 ai đó, thì việc chúng ta cần làm là nói với ngôi sao đó: “Đây! Địa chỉ của tui đây”. Cung cấp cho Java đường dẫn tới class com.edward.tutorial.di.Main chứa hàm main. Việc còn lại cứ để Java lo, Java sẽ gọi hàm main trong class com.edward.tutorial.di.Main và “Developer’s dream” will be started. LƯU Ý: Hollywood principle chỉ là cách gọi khác của Dependency inversion principle. Thêm 1 ví dụ dễ thấy.

JButton helloButton = new JButton("Hello");
helloButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("I would say Hello to everyone!");

Chúng ta không hề gọi hàm actionPerformed(ActionEvent e), mà chỉ khai báo như vậy, và nói: “Hey! Java Swing or EventDispatchThread or something like that, call me when someone click the helloButton”. Một lần nữa, Java sẽ lo việc đó.

Inversion of Control Container (IoC Container)

Chúng ta đã thấy sự tuyệt vời với những đoạn code ở trên, Inversion of Control Container chính là những ngôi sao Hollywood thực thụ, họ định nghĩa ra Hollywood principle, công việc của lập trình viên là: viết ra những đoạn code và nhờ IoC Container đâu là điểm entry point Trong Eclipse, chúng ta dễ dàng config entry point cho 1 chương trình Java tại: Config_Main

Inversion of Control Container Framework (IoC Container Framework)

Trong ứng dụng Java truyền thống, IoC Container có thể được hiểu như những ví dụ ở trên. Tuy nhiên, trong những ứng dụng Java Enterprise, IoC Container mới có nhiều đất diễn, có khá nhiều Framework hỗ trợ IoC Container tạm gọi là IoC Container Framework như: JEE Framework hoặc Spring Framework. Nơi mà những khái niệm về: Dependency Injection, Inversion of Control hay Inversion of Control Container sẽ được nhắc đến như là những Core Feature. Tất cả đều hướng đến một mục đích duy nhất: tạo ra ứng dụng loosely coupling, flexibility cũng như giúp lập trình viên tập trung 99% vào công việc cho business flow.

Loosely coupling và Testing

Một lợi ích không thể nhắc đến khi thiết kế chương trình theo loosely coupling style chính là Testing. Thay vì phải inject những đối tượng thực vào trong SUT (System under test, hay nôm na là class cần test), chúng ta có thể inject các stub đã implement interface vào trong SUT. Chi tiết sẽ được bàn trong bài viết về UnitTesting. 🙂

Learn from Question&Answer

Có một bạn hỏi như sau:
Nói về chủ đề này, với DI thì ok. Bài viết này của anh khá sâu, tuy nhiên phần ioc lại chưa đc rõ rằng lắm. Vẫn còn khá chung chung. A có thể giải thích cho em vài vấn đề sau. Giữa DI và ioc
1. Thằng nào là con thằng nào?. Quan điểm con của nhau có đúng ko?.
2. Theo em đc biết, DI là 1 design pattern xây dựng lên để đáp ứng cho tính lỏng lẻo, giảm sự liên kết phụ thuộc và khi đó IoC chính là thằng thực hiện theo cái DI đó, nó sẽ sử dụng BeanFactory và ApplicationContext để thao tác lấy thông tin từ XML xử lý, tạo đối tượng. Khi đó, với quan điểm của em thì em nghĩ chẳng thằng nào là con thằng nào cả.

Một câu hỏi khá hay. Trong cái thắc mắc của em đã trả lời luôn rồi.
Đúng như em nói: DI là 1 Design Pattern “để đáp ứng cho tính lỏng lẻo, giảm sự liên kết phụ thuộc”. IoC thì rộng hơn, và thường đi liền với Framework. Framework sẽ invert và control phần xương sống của application được develop bên trên, và “chừa”, “cung cấp” 1 số “cổng” để developer có thể inject phần implement của mình vào application. (Inject ở đây có 2 cách hiểu như 2 ví dụ dưới đây.

1. BeanFactory và ApplicationContext: em đang nói đến Spring Framework, vậy đó, Spring cho phép em inject các implementation của mình vào application qua ApplicationContext và 1 số Bean XML. Rõ ràng, DI được dùng để làm chuyện này thông qua @Autowired hay @Inject (CDI)

2. Tuy nhiên, trong bài viết của anh còn đề cập đến một chuyện đơn giản hơn. Đó là Java Swing Framework. Swing cho phép chúng ta định nghĩa ra “những action to be peformed” khi 1 event cụ thể được fired. Còn việc fire đó sẽ do Swing chứ ko phải do mình. DI không được dùng trong đây, nghĩa là Swing không cần đến pattern DI mà vẫn làm được việc Invertion of Control.
Từ 2 ví dụ trên có thể cho em hiểu Invertion Of Control là gì và mối quan hệ với DI rồi nhé.

Kết thúc bài tại đây, hi vọng trong giới hạn hiểu biết cùng với cách giải thích của mình sẽ giúp các bạn có thêm 1 cái nhìn khác về các khái niệm: Dependency Injection, Dependency Inversion Principle, IoC.. Trong những bài sau, chúng ta sẽ bàn luận về IoC Container trong Spring Framework. Happy learning


Chưa phân loại

I Don’t Write Unit Tests Because…. : The Excuses


As someone who’s seen the benefits of the approach, I’m a huge believer in test driven development. It adds a level of quality and maturity to the field of software development, yet it’s still not a widespread practice across development projects. When it comes to a choice between the features, time and quality, it’s always the quality that suffers. We don’t want to add extra time for testing and we don’t want to compromise on the feature set of the delivery. If you haven’t set out to do test driven development at the start of the phase, then it’s difficult to fit in.

We’ve all heard excuses for not taking the test driven approach, but nowhere compiles them better than “Pragmatic Unit Testing in Java With JUnit“, from the Pragmatic Bookshelf.  I read the book a few years ago, and afterward I thought there was no way that any responsible developer could read the book without truly believing that unit tests were one of the most important aspects of the development activity.

The most worrying excuse I’ve heard is that it’s too difficult to test my code. This can be for one of two reasons. One is that your code is mainly UI related, and automating the UI tests is too difficult. I’ll concede that UI automation is a tricky area (but not impossible, as we’ll see in a later article), but every effort should be made to automate it if possible: think about regression tests. If you have a fully automated test suite, including the UI behaviour, you can make a change to your code, and have full confidence that you haven’t broken anything if you have tests to re-run.

The second reason that your code is too difficult to test is that you’ve messed up your design. Maybe your logic and UI code are too tightly coupled, and without that automated UI layer existing, the dependency between the logic and the UI will cause a problem. This is where test driven development helps to ensure a clean design, following best practices. Using JUnit is simple, so if I can just point my test at a clean logic layer, I can test all logic that the UI will ever touch.  What’s that? You’re missing your data model? Well then just use mock objects – there are many frameworks for that!

For those who haven’t read the book yet, I’ll give a quick summary of the excuses for not testing as outlined in the introduction chapter:

I don’t have time to unit test.
Really? But you have to time to fix your mistakes later?  The simple fact is that nobody, not even you, can write bug free code.  Unit tests greatly speed up the time it takes to identify a bug because they narrow the suspect code down to a very specific unit.  Other types of testing, such as Quality Assurance or User Acceptance Testing, identify problems at a much higher level, forcing the developer to spend extra time plodding through the various units looking for the root cause. Unit tests can also serve as verification that the bug is corrected without having to go through the hassle of creating a new application build and deploying it for further testing.  Simply put, unit tests speed up overall development.  It might take slightly longer to create each new feature, but the development time for the entire application, from inception to delivery, is considerable shorter.
The client pays me to develop code, not write unit test.
News Flash – Unit tests are code.  They are as integral to the application as any other piece of code you are writing, and should be included in the original estimate and statement of work.  It might also help to mention to the client that unit tests lower both development cost (see previous excuse) as well as maintenance cost.  If you are not writing unit tests, then you are doing your client an injustice by forcing them to incur extra expense.
I am supporting a legacy application without unit tests.
That still doesn’t preclude you from writing your own.  Granted, you are not going to be able to go in and write tests to bring the entire code base up to an acceptable level of coverage.  You most likely don’t have the time or resources to do that.  But as support issues are raised, write the unit tests for any code that you modify.  When I am working on a support task, one of the very first things I do is write a unit test to recreate the bug.  When the unit test starts passing, I know that I have fixed the problem.  Now, not only have I resolved a bug, but I have added some unit test coverage to the code base.  Over time, this coverage will become more and more robust, and actually reduce future maintenance costs by preventing the introduction of regression bugs.
QA and User Acceptance Testing is far more effective in finding bugs.
No arguments there.  But Unit Testing is far more effective at preventing bugs.  Just because my smoke alarm is better at detecting potential fires doesn’t mean that it is safe to leave the stove on all the time.  QA and UAT are smoke alarms – they alert you to potential existing trouble.  Unit testing is turning off the stove when you are done – it helps you prevent trouble.  Unit testing, QA, and UAT are all important parts of the testing process, and they each play very different roles.  Trying to replace one with another doesn’t work.  I wouldn’t release a project that was well unit tested without QA, and I wouldn’t release a project that was thoroughly QA’ed without unit testing.
I don’t know how to unit test, or I don’t know how to write good unit tests.
Well, this is probably the most valid excuse that is out there.  The sad truth is that a great many number of developers and engineers do not know how to unit test.  I didn’t when I started.  And nothing discourages a developer more than struggling to write bad unit tests.  Luckily there are resources out there.  There are so many books, webinars, conference presentations, blogs, etc on writing good unit tests that the inability to write them simply isn’t going to cut it as an excuse any more.  When someone offers me this excuse, I don’t look at it as a roadblock, but rather as a teachable moment.  It usually only takes a time or two of seeing how well written unit tests can help one develop code to turn them from the dark side…

Are there other excuses out there?  Absolutely.  But they are just that – excuses.  I have yet to encounter a valid reason to skip unit testing.  If you think you have one, post it here.  I look forward to the challenge of changing your mind! 🙂


Lập trình theo kiểu Aspect Oriented Programming (AOP) sử dụng Spring Framework

Aspect Oriented Programming

Trong khoảng 5 năm trở lại đây, một khuynh huớng lập trình mới xuất hiện. Nó được gọi là AOP để phân biệt với kiểu lập trình OOP đã có sẵn. Nguời viết muốn cung cấp cho bạn đọc một kiến thức cơ bản về kiểu lập trình mới mẻ này, và sử dụng springframework, một open-source phổ biến, để minh hoạ. Nếu bạn muốn tìm hiểu chi tiết về cách sử dụng springframework, thì bài viết này không nhằm mục đích đó, mà chỉ trình bày khái quát về những thuật ngữ và nguyên tắc trong việc sử dụng 1 chức năng phổ biết của spring: declarative transaction .

Aspect Oriented Programming (AOP) và Object Oriented Programming (OOP)

Một điểm quan trọng nữa cần đuợc nêu ra, AOP đuợc xem là cái bổ sung cho OOP, chỗ mà OOP còn thiếu sót trong việc tạo những ứng dụng thuộc loại phức tạp. AOP khônng phải là cái thay thế OOP. Nguời lập trình bắt buộc phải quen thuộc với OOP để bắt đầu với AOP. Cũng vì lí do này mà AOP thuờng đuợc xem là dành cho các bạn đã có kinh nghiệm, chứ không dành cho các bạn mới bắt đầu làm quen với Java. Bạn có thể làm quen với OOP qua lí thuyết và sách vở từ truờng học. Và nếu bạn thấy vẫn còn lạc lối trong việc tìm kiếm những danh từ, tính từ, hay trả lời những câu hỏi ai, cái gì, làm gì… đại loại như vậy, trong việc tìm kiếm class, thì bạn có thể đọc lại những bài viết về OOP mà nguời viết đã trình bày truớc đây xem có giúp ích hơn không. Dù học OOP theo kiểu nào thì kết quả cuối cùng của OOP là chia ứng dụng thành nhiều phần nhỏ với những chức năng riêng biệt, theo kiểu các hộp đen (black box). Các hộp đen này làm cho việc tái sử dụng và bao quản chúng đuợc dễ dàng hơn….và còn thêm nhiều ưu điểm khác nữa không kể ra ở đây.

Hạn chế của Object Oriented Programming

Lấy ví dụ về transaction trong việc truy cập database. Trong Java, truy cập database đòi hỏi nhiều buớc: tạo ra Connection, bắt đầu transation, commit, clean up connection… Để đơn giản hoá, ta hãy tạo ra 1 class hay black box chuyên làm việc này.

public class DBTransaction {
     public DBTransaction () {
          //mã nguồn tạo ra Connection và bắt đầu 1 transaction

     public Connection getConnection () {
          //mã nguồn return Connection đã tạo ra

     public void commit () {
          //mã nguồn commit transaction và clean up resources

Giả sử trong 1 ứng dụng, có 1 class (hay blackbox) XuatNhapHang làm chức năng xuất nhập hàng và nó chứa 1 method làm chức năng nhập hang.

public void nhapHang ( int monHang, int soLuong )
     //sử dụng blackbox để bắt đầu 1 transaction
     DBTransation tx = new DBTransactiơn ();

     // ...mã nguồn truy cập database để nhập hàng...

     tx.commit ();

Bạn dễ dàng hình dung đuợc mục đích sử dụng của blackbox này.
Mỗi khi cần truy cập database, nguời sử dụng chỉ việc gọi các public methods của nó mà không cần biết tới bên trong nó hoạt động ra sao. Việc thay đổi bên trong của blackbox cũng không làm ảnh huởng tới nguời sử dụng nó. Đó là cái đẹp của việc tạo ra blackbox. Mọi nguời hình như đều vui vẻ và độc lập với công việc của mình. Thực tế không hoàn toàn như vậy. Giả sử ứng dụng sau này đòi hỏi phải theo dõi tất cả mọi hoạt động liên quan đến việc truy cập database. Mỗi khi database đuợc truy cập, tên nguời sử dụng và thời gian sẽ đuợc lưu trữ lại. Ta có thể tạo ra 1 blackbox đơn giản chuyên làm việc này.

public class DBTruyCapTheoDoi {
     public DBTruyCapTheoDoi (Connection con, String tenNguoi) {
          //mã nguồn lưu lại trong database nguời sử dụng và thời gian

Method nhapHang hay những nơi trong ứng dụng đã truy cập database đều phải sửa đổi như sau

public void nhapHang ( int monHang, int soLuong )
     //sử dụng blackbox để bắt đầu 1 transaction
     DBTransation tx = new DBTransactiơn ();
     //theo doi truy cap
     DBTruyCapTheoDoi (tx.getConnection (), tenNguoi);

     // ...mã nguồn truy cập database để nhập hàng...

     tx.commit ();

Sửa đổi không nhiều nhưng nó rộng khắp trong toàn ứng dụng. Đây chính là điểm làm cho nhiều nguời không hài lòng. Những nguời lập trình kì cựu đều đồng ý với nhau rằng, trong thực tế, đòi hỏi của ứng dụng luôn thay đổi theo thời gian. Cứ mỗi 1 yêu cầu mới của ứng dụng thì một (hay nhiều) blackbox đuợc tạo thành, và mã nguồn sẽ bị thay đổi rộng khắp trong ứnng dụng để sử dụng blackbox mới này. Thay đổi mã nguồn rộng khắp ứng dụng là điều tối kị vì nó đòi hỏi phải testing lại toàn bộ . Những bug xuất hiện lúc này thuờng rất khó tìm vì nguời lập trình thuờng cho rằng “mình sửa có 1 chút thì không sao…” .

Câu hỏi đặt ra là làm sao tạo đuợc một kiểu lập trình uyển chuyển với sự phức tạp của ứng dụng . Mô hình này phải cho phép tạo dựng nhanh chóng ứng dụng khi nó ở trong giai đọan đầu đơn giản, và thay đổi nhanh chóng để thích ứng kịp thời với đòi hỏi mới . OOP cho phép tạo ra những blackbox và điều này vẫn đuợc xem là không thể thiếu trong việc lập trình . Bản thân những blackbox không phải là vấn đề, mà chính việc sử dụng chúng mới là vấn đề . Việc gọi trực tiếp những public method của 1 blackbox khi phải sử dụnng nó trong mã nguồn, tạm gọi là nối cứng (hard wired) blackbox vào mã nguồn. Có cách nào để sử dụng 1 blackbox mà khônng cần gọi trực tiếp nó trong mã nguồn hay không? Cần có 1 cách nào đó để gọi gián tiếp những public method, hay tạm gọi là nối mềm (soft wired) khi sử dụng những blackbox. Đây là chỗ OOP bỏ sót, và AOP ra đời để đáp ứng nhu cầu này .

Đến đây bạn có thể thấy rằng, OOP là buớc đầu tiên cần phải có để tạo thành các blackbox. AOP là buớc kế tiếp để nối mềm những blackbox tạo thành 1 ứng dụng hoàn chỉnh . Việc nối mềm đòi hỏi nguời thiết kế phải có kinh nghiệm trong việc chia ứng dụng thành nhiều lớp (layer) để ứng dụng đuợc tạo ra và chạy 1 cách hữu hiệu . Điều này sẽ đuợc nói kĩ hơn sau đây. Một rắc rối nữa của việc nối mềm là nó thuờng đòi hỏi tạo nhiều cấu hình (configuration) phụ trợ .

Làm thế nào để nối mềm 1 ứng dụng?

Đây cũng chính là câu hỏi mà AOP cần phải trả lời . Java cho phép là đuợc việc này .

Nối mềm là cho phép sử dụng 1 class (hay blackbox) mà không cần gọi trực tiếp public methods của nó trong mã nguồn, và bạn có thể ngạc nhiên nếu biết rằng điều này thực sự đã đuợc làm từ lâu . Nó đuợc làm bởi các container chẳng hạn như của EJB, portlet, servlet. Lấy EJB container làm ví dụ, vì nó rất gần với khái niệm AOP . Muốn sử dụng 1 EJB, bạn phải gọi create… chứ không bao giờ sửng dụng new . EJB trong thực tế chạy bên trong 1 container. Container trực tiếp tạo ra instance của EJB và chuyển cho nguời sử dụng khi method create… được gọi . Mỗi lần nguời sử dụng gọi method của EJB, container sẽ đón đầu (intercept) cú gọi này, rồi mới chuyển giao cho instance của EJB . Truớc khi chuyển giao cho EJB, thuờng container có thể sẽ làm nhiều việc khác nữa …. Container có thể bắt đầu 1 transaction, hay kiểm tra xem nguời gọi có đuợc phép gọi hay không, tùy theo cách cấu hình của EJB đó bên trong file ejb-jar.xml . Nếu xem EJB là 1 blackbox thì việc nối giữa EJB và nguời sử dụng nó mặc dù là gián tiếp nhưng chưa đuợc xem là nối mềm . Bản thân EJB container có thể chứa sẵn bên trong nó 1 blackbox làm công việc bắt đầu 1 transaction, hay 1 blackbox khác làm công việc kiểm tra mức độ cho phép nguời gọi . Việc nối kết giữa EJB và những blackbox bên trong của container mới chính xác là mềm … Bản thân EJB hay nguời viết nó hoàn toàn không biết đến có tồn tại 1 blackbox có sẵn bên trong container làm công việc transaction . Nguời viết EJB chỉ việc thông tin với container qua file cấu hình ejb-jar.xml rằng phải bắt đầu 1 transaction hay làm thêm những chuyện khác mỗi khi method của nó đuợc gọi . Cũng dựa trên ý tuởng này, spring framework chính là 1 container thuộc loại nhẹ và nó có thể chứa đựng những Java object thông thuờng chứ không phức tạp như EJB .

Trở lại ví dụ xuất nhập hàng ở trên, nếu class XuatNhapHang chạy bên trong spring framework thì method nhapHang ở trên có thể viết lại như sau

public void nhapHang ( int monHang, int soLuong )
     // ...mã nguồn truy cập database để nhập hàng...

Không hề có 1 đọan mã nguồn nào bên trong method nhapHang nói đến việc tạo ra transaction hay theo doi truy cap . Bản thân các blackbox transaction và theo dõi try cập cũng đuợc chạy trong spring. Nguời viết class XuatNhapHang chỉ việc truyền đạt cho spring, qua 1 file cấu hình, rằng mỗi khi method nhapHang đuợc gọi , hãy gọi blackbox transaction và theo dõi truy cập truớc khi chuyển nó đến nhapHang . Bằng cách nối mềm này, việc bao gồm hay loại bỏ những blackbox đuợc thực hiện qua việc thay đổi file cấu hình, chứ không cần phải thay đổi mã nguồn của class XuatNhapHang . Đây chính là lập luận mạnh nhứt trong việc cho ra đời AOP . Những nguời ủng hộ AOP trong ví dụ này lí luận rằng class XuatNhap hay method nhapHang chỉ nên lo lắng việc xuất nhập hàng . Việc bắt đầu 1 transaction hay theo dõi truy cập dữ liệu , đành rằng phải có do yêu cầu của ứng dụng, cũng không nên chen lấn 1 cách thô bạo vào trong mã nguồn của class XuatNhap, hay bất kì vào trong những blackbox nào khác khi chúng cũng cần truy cập dữ liệu . Có như vậy thì 1 blackbox mới giữ đuợc tính độc lập của nó với những thay đổi của yêu cầu của ứng dụng, dẫn đến việc tái sử dụng blackbox đuợc triệt để hơn .

Những khía cạnh như transaction hay theo dõi truy cập, nếu cần phải ‘chen lấn ‘ thì mã nguồn không phải là chỗ tốt để làm . Có những chỗ tốt hơn chẳng hạn như dùng file cấu hình, và spring framework làm đúng như vậy . Công việc của spring framework là đón đầu các cú gọi và thực hiện các chức năng thể hiện qua file cấu hình . Đây cũng chính là nguyên tắc cơ bản của AOP: thay các cú gọi trực tiếp, bằn các cú gọi qua file cấu hình ..

Khó khăn khi áp dụng Aspect Oriented Programming

Đọc đến đây, có thể bạn không mấy hào hứng với AOP . Thực tế các file cấu hình cho spring hay các AOP framework khác như AspectJ không đơn giản chút nào . Gọi trực tiếp method chỉ mất 1 dòng và cũng dễ theo dỏi logic của ứng dụng . Thay đổi file cấu hình liệu có an toàn hơn thay đổi mã nguồn hay không ? Những nguời ủng hộ AOP thì cho rằng nó rất nên làm . Những nguời còn hoài nghi thì luỡng lự . Các AOP framework khác nhau đều có cách tạo file cấu hình khác nhau. Không giống như EJB có thể chạy trong mọi EJB container, ứng dụng viết cho AOP framework này không chạy đuợc trong AOP framework khác . Những cố gắng để thống nhứt các AOP framework cho đến bây giờ vẫn chưa kết thúc . Việc container đón đầu các cú gọi có thể ảnh huởng đến tốc độ chạy của ứng dụng . Thêm nữa, không phải mọi class trong ứng dụng đều cần đuợc quản lí bởi AOP framework cũng như không phải mọi class đều trở thành EJB. Nếu ứng dụng thiết kết kém cỏi có thể dẫn đến số luợng class mà AOP container phải quản lí cùng với các file cấu hình tăng lên nhanh chóng . Có lẽ cũng chính vì những lí do này mà AOP vẫn chưa cất cánh nhanh chóng như OOP . Điểm khó khăn cuối cùng nữa của AOP là lí thuyết hoá nó để truyền đạt . AOP đưa ra những khái niệm lạ hoắc khó nắm bắt, dễ làm nản lòng những nguời mới bắt đầu . Phần kế tiếp nguời viết sẽ trình bày những khái niệm cơ bản của AOP, và nguyên tắc Inversion of Control hay còn gọi là Dependency Injection của springframework trong việc triển khai AOP .

Những khái niệm trong Aspect Oriented Programming

Khái niệm đầu tiên thuờng gặp trong AOP là concern (1 mối lo âu) hay aspect ( 1 khía cạnh của vấn đề). Concern hay aspect trong AOP chỉ là 1, và nó tuơng đuơng với chức năng của 1 blackbox trong OOP. Lấy ví dụ trong ứng dụng cho 1 cửa hàng mua bán . Những yêu cầu của ứng dụng bao gồm : chi thu tài chính, xuất nhập hàng, kết toán cuối tháng, cuối năm, quản lí nhân viên … Và có thể thay đổi trong tuơng lai theo yêu cầu của thực tế . Việc chia nhỏ 1 yêu cầu cùng với OOP sẽ đưa đến các blackbox như xuất nhập hàng, transaction, hay theo dõi truy cập như ở trên . Chức năng của mỗi blackbox có thể đuợc xem là 1 khía cạnh của ứng dụng mà nguời thiết kế phải lo lắng . Tới đây bạn có thể thấy vì sao 2 chữ concern và aspect mang nghĩa không mấy ăn nhập với nhau lại đuợc dùng để chỉ chung 1 khái niệm . Có những khía cạnh, như transaction, cần phải ‘chen lấn ‘ vào các khía cạnh khác . Những khía cạnh đó đuợc gọi là crosscutting aspect, tạm gọi là những khía cạnh cắt ngang . Trong thực tế, điểm chen lấn của những crosscutting aspect không tùy tiện mà nó thuờng là các điểm đặc biệt . Ví dụ như khía cạnh trasaction chỉ chen vào khi bắt đầu method nhapHang để khởi tạo 1 transaction và lại chen vào 1 lần nữa khi method nhapHang return để commit transaction. Những điểm đặc biệt có thể kể ra là bắt đầu hay kết thúc 1 method, khi xảy ra exception. Spring chỉ cho phép chen vào các điểm đặc biệt, còn AspectJ thì cho phép hầu như vào bất cứ điểm nào trong mã nguồn . Việc chen lấn tuỳ tiện cần được cân nhắc kĩ lưỡng và thuờng đuợc khuyên nên tránh . Điểm chen lấn đuợc gọi là joinpoint (điểm nối ) . Tập họp các điểm nối đuợc gọi là pointcut (cắt điểm). Bản thân blackbox XuatNhapHang bị chen lấn nên nó đuợc gọi là target object. Bản thân blackbox transaction, triển khai transaction aspect, làm công việc chen lấn, đuợc gọi là advice. Vì có nhiều điểm chen lấn đặc biệt kể trên, nên có nhiều loại advice.
_ Around advice: là loại chen vào truớc khi cú gọi đuợc chuyển tới method và sau khi method thực hiện xong. Transaction advice chính là loại này
_ Before advice: chen vào truớc khi cú gọi đuợc chuyển tới method
_ Throws advice: chen vào khi bản thân method thows excpetion
_ After returning advice: chen vào sau khi method thực hiện và không có exception .

Ta có thể hình dung như sau: mỗi khi ứng dụng gặp điểm ‘chen lấn ‘, container sẽ đón đầu cú gọi và chạy mã nguồn của advice cho điểm ‘chen lấn ‘ đó rồi mới chuyển giao cho method.
Tới đây có lẽ khá đủ cho nguời mới làm quen với AOP. Để thực sự có thể lập trình theo kiểu AOP, bạn cần phải thông thạo với 1 AOP framework như spring hay aspectJ, đặc biệt là cách tạo file cấu hình cho mỗi framework.

Trở lại spring framework, nó đuợc đề cập ở đây vì 1 chức năng phổ biến : declarative transaction, giống như trong EJB, nhưng đơn giản và dễ sử dụng hơn nhiều. Để sử dụng chức năng này, chỉ cần khái niệm của AOP ở trên là đủ . Khi sử dụng spring, 1 khái niệm luôn gặp phải là Inversion of Control (IoC) hay còn gọi là Dependency Injection, nó sẽ đuợc nói rõ duới đây .

Inversion of Control (IoC) và Dependency Injection (DI)

IoC (tạm dịch là đảo nguợc kiểm soát) thuờng được thực hiện bởi các loại container như servlet, portlet, hay EJB.

Lấy ví dụ EJB container, nguời sử dụng không trực tiếp tạo ra instance của EJB, mà container tạo ra nó và chuyển giao nguời sử dụng khi cần tới . Khi nào instance đuợc tạo ra nằm ngoài sự kiểm soát của nguời sử dụng . Container có thể tạo instance ra truớc và chờ đến khi nguời sử dụng, hoặc tạo ra ngay vào lúc đuợc cần tới . Tên gọi IoC cũng nhằm chỉ lí do này: container giành sự kiểm soát từ nguời sử dụng (trong lập trình thông thuờng nguời sử dụng giành kiểm soát bằng cách gọi new để tạo ra instance). Khi instance của EJB đuợc tạo ra và trong truờng hợp session bean, container luôn gọi method setSessionContext(SessionContext sc) để cho EJB sử dụng SessionContext của nó .

Tuơng tự trong servlet container, khi instance của servlet đuợc tạo ra, container luôn gọi method init(ServletConfig sc) để servlet sử dụng . Trong cả 2 truờng hợp, container đuợc xem là nạp (injection) cho instance cái mà nó cần . Cái đuợc cần như SessionContext hay ServletConfig gọi là dependency .

Tên gọi Dependency Injection cũng từ đây mà ra. Có 1 điểm bất đồng giữa cách gọi tên Dependency Injection và định nghĩa về mối quan hệ giữa class trong UML . Dựa trên tài liệu “Mastering UML with Rational Rose” thì instance của EJB sử dụng SessionContext nên instance mới chính là dependency phụ thuộc vào SessionContext . Nếu bạn giải thích đuợc tại sao có sự bất đồng này thì làm ơn cho mọi nguời cùng biết . Dù sao thì chúng ta không nên mất quá nhiều thời giờ cho vấn đề định nghĩa và tên gọi ở đây .

Aspect Oriented Programming trong Spring Framework

Muốn sử dụng Spring, ít nhiều bạn phải làm quen với Spring container . Class tiêu biểu cho spring container là ApplicationContext . Nguời sử dụng phải trực tiếp tạo ra instance của spring container truớc khi có thể sử dụng những object mà nó chứa . Có nhiều cách tạo ra spring container. Cách thông thuờng nhứt là (những ví dụ theo sau đuợc dựa trên tài liệu spring-reference.pdf vversion 1.2.8)

ApplicationContext ac = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "applicationContext-part2.xml"});

Spring container tạo ra theo cách này sẽ đọc những file config duới dạng xml để load tất cả các Java ojbect mà nó cần quản lí .
Như ví dụ sau

<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

ExampleBean và ExampleBeanTwo có thể là những java object thông thuờng chứ không có gì đặc biệt . Muốn truy cập chúng qua container rất dễ dàng

ExampleBean eb = (ExampleBean)ac.getBean("exampleBean");
ExampleBeanTwo eb2 = (ExampleBeanTwo)ac.getBean("anotherExample");

Theo mặc định thì container sẽ tạo ra singleton instance cho mỗi bean, có nghĩa là chỉ 1 instance của 1 bean đuợc tái sử dụng cho những lần gọi sau . Ta có thể sử dụng Dependency Injection của container như sau

<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<property name="beanTwo"><ref bean="yetAnotherBean"/></property>
<property name="integerProperty"><value>1</value></property>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
     private AnotherBean beanOne;
     private YetAnotherBean beanTwo;
     private int i;

     public void setBeanOne(AnotherBean beanOne) {
          this.beanOne = beanOne;
     public void setBeanTwo(YetAnotherBean beanTwo) {
          this.beanTwo = beanTwo;
     public void setIntegerProperty(int i) {
          this.i = i;

Bản thân ExampleBean phải chứa những setter method để container gọi ngay sau khi tạo ra chúng và truớc khi chuyển cho nguời sử dụng .

Nguyên tắc sử dụng spring container chỉ đơn giản như vậy thôi . Nó cho phép định nghĩa qua file cấu hình những logic phức tạp hơn mà bài viết không trình bày hết ra đây . Tới đây bạn có thể thắc mắc như vậy thì sức mạnh của spring nằm ở đâu ? Tiện lợi chỉ đơn giản như vậy thì có đáng đuợc sử dụng không ?

Cần nhắc lại 1 nguyên tắc làm việc của mọi dạng container là đón đầu những cú gọi . Spring làm việc này bằng cách dựa trên file cấu hình để tạo ra những object phụ trợ khác vào lúc runtime . Cái return từ method getBean đuợc xem là 1 proxy đuợc tạo ra vào lúc runtime của java object mà spring quản lí . Đằng sau proxy này là 1 tập họp các phụ trợ object thực hiện các chức năng theo yêu cầu của file cấu hình truớc khi chuyển cú gọi tới cho java object . Chẳng hạn như các phụ trợ object có thể chạy mã nguồn của advice, hoặc bắt đầu 1 transaction, một chức năng đã được làm sẵn trong Spring, sẽ đuợc nói tới duới đây .

Trong việc truy cập database, ứng dụng có thể sử dụng các phuơng pháp khác nhau như: trực tiếp sử dụng SQL, Hybernate, EJB Entity … Để đơn giản hoá vấn đề, ta lấy truờng sử dụng SQL để cập nhật database .

Trong Java, connection thường tạo ra duới dạng connection pool hay DataSource, là 1 tập họp những connection để xử dụng chung cho toàn bộ ứng dụng . Giả sử apache datasource đuợc xử dụng ở đây . Để container có thể tạo ra datasource cho oracle, ta xử dụng cấu hình duới đây

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//localhost:1521"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>

Nếu datasource đã đuợc tạo ra xử dụng JNDI, ta có thể dùng cấu hình

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryB ean">
<property name="jndiName" value="jdbc/jpetstore"/>>

Bản thân datasource sẽ đuợc xử dụng bởi 1 transaction manager, 1 object quản lí transaction có sẵn trong spring như sau:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSou rceTransactionManager">
<property name="dataSource" ref="dataSource"/>

Trở lại class XuatNhapHang ở trên, muốn spring tự động bắt đầu và kết thúc 1 transaction mỗi khi 1 method của class này đuợc gọi , cần có những cấu hình cho pointcut hay advice khá phức tạp theo kiểu AOP . Rất may là spring đã gói gọn trong 1 class TransactionProxyFactoryBean đơn giản sau

<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<prop key="*">PROPAGATION_REQUIRED, -MyException</prop>

Chúng ta sẽ kiểm tra kĩ lưỡng cấu hình này .
_ abstract=”true” có nghĩa là ứng dụng không đuợc phép gọi method getBean(“txProxyTemplate”) . Cấu hình này chỉ đuợc dùng để các cấu hình khác extends . Giống như tính chất inheritance trong OOP
_ property name=”transactionManager” ref=”txManager” cho biết class TransactionProxyFactoryBean sẽ đuợc nạp bean txManager bởi container.
_ prop key=”*” : áp dụng cho mọi method của những class extends cấu hình này
_ PROPAGATION_REQUIRED: bắt đầu 1 transaction nếu chưa có hoặc tiếp tục 1 transaction có sẵn .
_ MyException: nếu method throw MyException, thì dấu – đằng truớc sẽ làm transaction bị rollback, và dấu + sẽ commit transaction truớc khi throw MyException.

Cấu hình của class XuatNhapHang sẽ extends cấu hình này như sau:

<bean id="xuatNhapBean" parent="txProxyTemplate">
<property name="target">
<bean class="XuatNhapHang"></bean>

Ứng dụng có thể xử dụng class XuatNhapHang như sau:

XuatNhapHang xnh = (XuatNhapHang)ac.getBean("xuatNhapBean");

Bằng cách extends cấu hình của txProxyTemplate qua việc sử dụng attribute parent, mỗi khi 1 method của class XuatNhapHang đuợc gọi, 1 transaction sẽ tự động bắt đầu và kết thúc . Transaction sẽ bị rollback trong truờng hợp exception MyException xảy ra . Spring còn giúp mô hình JDBC operations như những java object qua việc xử dụng class MappingSqlQuery, SqlUpdate, StoredProcedure .

Bài viết đuợc kết thúc ở đây chỉ với mục đích giúp bạn làm quen với những khái niệm của AOP . Vì AOP là cái bổ sung cho những thiếu sót của OOP, AOP không dành cho những bạn mới bắt đầu lập trình . Spring framework mặc dù triển khai AOP đơn giản hơn so với AspectJ, cũng khác phức tạp với rất nhiều chức năng có thể dùng đuợc, và nguời viết chỉ tóm tắt 1 chức năng phổ biến nhất của nó là declarative transaction. Dù sao thì bạn vẫn cần tham khảo những tài liệu huớng dẫn về Spring truớc khi có thể dùng nó 1 cách hữu hiệu . Chúc bạn may mắn.

Sưu tầm


Java 8 Tutorial: Trọn bộ Java 8 new features từ Pluralsight

Giới thiệu


Hôm nay mình sẽ share một bộ video Trọn bộ Java 8 new features từ Pluralsight . Với hơn 4 giờ học, các bạn sẽ nắm được tất cả những đặc điểm nổi bật nhất trong Java 8 như Lambda Expression, Stream, Date and Time API, …

This course covers the most useful parts of Java 8. This update of the Java platform is the biggest of all. It’s even bigger than Java 5 that saw the introduction of generics. We’ll begin with lambda expressions and the Stream API, which bring new fundamental patterns to the Java platform. Many problems solved with the Iterator pattern are now solved much more efficiently with the patterns brought by the Stream API. But Java 8 is not only about lambdas, streams and collectors, there is also a new Java Date and Time API which are covered in this course. This API fixes all the flaws of the previous Date/Calendar API and brings new, very useful, concepts and tools. Many new features that bring a functional programming approach have been added to the Collection API. This is also covered in detail. Many more things are covered; little things, scattered here and there in the JDK, like this new StringJoiner class, useful to join strings with a prefix, a postfix, and a separator. JavaFX and Nashorn are also quickly covered, to show the FXML way to describe Graphical User Interfaces, and the new ways to describe JavaFX in Javascript using Nashorn.



Link GoogleDrive

Nội dung chi tiết

Introduction to Lambda Expressions in Java 8

  • Introduction, Targeted Audience
  • Module Outline
  • The FileFilter Example
  • A First Lambda Expression
  • Live Coding: A First Lambda Expression
  • Live Coding: Runnable and Comparator Examples
  • Several Ways of Writing Lambda Expressions
  • Three Questions About Lambda Expressions
  • Functional Interfaces
  • Is a Lambda Expression an Object?
  • The Functional Interfaces Toolbox
  • Method References
  • Processing Collections With Lambdas
  • Changing the Way Interfaces Work?
  • Default and Static Methods in Java 8 Interfaces
  • New Patterns: The Predicate Interface Example
  • Live Coding: New Patterns Examples
  • Module Wrap Up

Java 8 Stream API and Collectors

  • Introduction, Module Outline
  • The Map / Filter / Reduce Algorithm
  • What Is a Stream?
  • Definition of a Stream in Java 8
  • Building and Consuming a Stream
  • Filtering a Stream
  • Live Coding: Consuming and Filtering a Stream
  • Lazy Operations on a Stream
  • Lice Coding: Intermediary and Terminal Operations
  • Wrapping up Intermediary and Terminal Operations
  • The Map Operation
  • The Flatmap Operation
  • Lice Coding: Map and Flatmap Examples
  • Wrapping Up Map and Filter on a Stream
  • Reduction, Functions, and Bifunctions
  • Reduction of the Empty Set: Identity Element
  • Optionals
  • Pattern for the Optionals
  • Wrapping Up Reduction Operations
  • Terminal Operations
  • Live Coding: Reductions, Optionals
  • Wrapping Up Operations and Optionals
  • Collectors, Collecting in a String, in a List
  • Collecting in a Map
  • Live Coding: Processing Streams
  • Wrapping Module

Java 8 Date and Time API

  • Introduction and Outline
  • The Old java.util.Date API
  • Why Does Immutability Matter?
  • The Instant Class and the Duration Class
  • The LocalDate Class and the Period Class
  • Live Coding: Local Dates and Periods Examples and Corner Cases
  • Computing Dates From Other Dates
  • The LocalTime Class
  • Dealing With Time Zones: The ZonedTime Class
  • Printing Dates and Times: The DateTimeFormatter
  • From Legacy Code to the New Date and Time API
  • Conclusion and Wrap-Up

Strings, IO, and Other Bits and Pieces

  • Introduction and Outline
  • Strings and StringJoiner
  • Java I/O: Reading Text Files
  • Java I/O: Exploring Directories
  • New Methods on Iterable, Collection, and List
  • Comparator: Patterns and Utilities
  • Numbers, Method References, and Hashcodes
  • Map: Enhancements of Existing Methods
  • Map: The Compute and Merge Methods
  • Live Coding: General Map Enhancements
  • Live Coding: Map Merging
  • Live Coding: Building Bimaps
  • Annotations
  • Conclusion and Wrap Up

Introduction to Java FX 8

  • Introduction and Outline
  • First Key Concepts on a Simple Example
  • Live Coding a Hello World Example
  • Setting Up an Interface Using the JavaFX API
  • Setting Up an Interface Using the FXML File
  • Controller and Dependency Injection
  • Live Coding: Setting Up a UI With FXML and Java Controllers
  • Conclusion and Wrap Up

Nashorn: A JavaScript Engine on the JVM

  • Introduction and Outline
  • jjs: The Nashorn REPL
  • Livecoding: The REPL in Action
  • Running Javascript in Java Classes
  • Writing and Launching JavaFX UI in Javascript
  • Live Coding: JavaFX With Nashorn
  • Conclusion and Wrap Up



Java 8 Tutorial: Lambda expression and Streams in Java 8


Giới thiệu

Hôm nay mình sẽ share một bộ video học Java 8 từ LiveLessions. Với hơn 3 giờ học, các bạn sẽ nắm được những đặc điểm nổi bật nhất trong Java 8 là Lambda Expression và Stream.

Tóm tắt nội dung

  • Cách sử dụng những đặc điểm quan trọng nhất trong Java 8: Lambda Expressions và Streams.
  • Những kỹ thuật sử dụng lambda expression: method references, lambda building blocks in the java.util.function package, effectively-final local variables, the @FunctionalInterface annotation, and higher-order functions.
  • Các method mới liên quan đến Stream: forEach, map, filter, reduce, etc.
  • Infinite (unbounded) streams
  • Parallel streams.
  • Lazy evaluation and short-circuit stream operations.
  • Những đặc điểm khác trong Java 8: Functional Interface và Optional class.


Bộ video này được upload trên Youtube bởi bạn Tiep Phan, mình xin mạn phép chia sẻ lại.

Nội dung chi tiết


  • Introduction to Java 8: Lambda Expressions and Streams LiveLessons

Lesson 1: Java 8: Installation, Setup, and Review of Supporting Topics

  • Learning objectives
  • 1.1 Getting Started with Java 8
  • 1.2 Java 8 References
  • 1.3 Quick Review of Pre-Lambda Handlers
  • 1.4 Quick Review of Building Generic Methods and Classes
  • 1.5 Wrap-Up

Lesson 2: Lambda Expressions Part 1 – Basics

  • Learning objectives
  • 2.1 Motivation and Overview
  • 2.2 Lambdas: Most Basic Form
  • 2.3 Type Inferencing
  • 2.4 Expression for Body: Implied Return Values
  • 2.5 Comparing Java and JavaScript Sorting
  • 2.6 Omitting Parens for One-Arg Lambdas
  • 2.7 Using Effectively Final Local Variables
  • 2.8 The @FunctionalInterface Annotation
  • 2.9 Method References
  • 2.10 The java.util.function Package
  • 2.11 Final Example
  • 2.12 Wrap-Up

Lesson 3: Lambda Expressions Part 2 – Lambda Building Blocks in java.util.function

  • Learning objectives
  • 3.1 Lambda Building Blocks in java.util.function: Overview
  • 3.2 Predicate
  • 3.3 Function and BiFunction
  • 3.4 Consumer
  • 3.5 Supplier
  • 3.6 BinaryOperator
  • 3.7 Wrap-Up

Lesson 4: Lambda Expressions Part 3

  • Learning objectives
  • 4.1 Variable Scoping
  • 4.2 Method References: Details
  • 4.3 Java 8 Interfaces: Default Methods and Static Methods
  • 4.4 Methods that Return Lambdas
  • 4.5 Wrap-Up

Lesson 5: Streams Part 1

  • Learning objectives
  • 5.1 Overview of Streams
  • 5.2 Getting Standard Data Structures Into and Out of Streams
  • 5.3 Core Stream Methods: Overview
  • 5.4 forEach – Calling a Lambda on Each Element of a Stream
  • 5.5 map – Transforming a Stream by Passing Each Element through a Function
  • 5.6 filter – Keeping Only the Elements that Pass a Predicate
  • 5.7 findFirst – Returning the First Element of a Stream while Short-Circuiting Earlier Operations
  • 5.8 Lazy Evaluation
  • 5.9 Wrap-Up

Lesson 6: Streams Part 2

  • Learning objectives
  • 6.1 reduce: Combining Stream Elements
  • 6.2 collect: Fancier Stream Output
  • 6.3 Operations that Limit the Stream Size: limit, substream
  • 6.4 Operations that Use Comparisons: sorted, min, max, distinct
  • 6.5 Operations that Check Matches: allMatch, anyMatch, noneMatch, count
  • 6.6 Parallel Streams
  • 6.7 Infinite (Unbounded On-the-Fly) Streams
  • 6.8 Wrap-Up


  • Summary of Java 8: Lambda Expressions and Streams LiveLessons