Spring reference I. Giới thiệu



tải về 261.07 Kb.
trang1/3
Chuyển đổi dữ liệu02.09.2016
Kích261.07 Kb.
  1   2   3

SPRING REFERENCE

I. Giới thiệu:


Spring framework chứa nhiều đặc tính, được tổ chứa thành 7 modules:

  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.

  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.



II. Các kỹ thuật cơ bản:





  1. IoC container

Hai package: org.springframework.beans và org.springframework.context cung cấp IoC container cho Spring framework. Giao tiếp BeanFactory cung cấp kỹ thuật cấu hình nâng cao, có khả năng quản lý các đối tượng. Giao tiếp ApplicationContext kế thừa từ BeanFactory và thêm một vài chức năng khác như tích hợp với đặc tính Spring AOP, truyền sự kiện, application context như WebApplicationContext sử dụng trong ứng dụng web.


1.1. Container và beans:
Các đối tượng trong ứng dụng được quản lý bởi IoC container được gọi là các bean. Một bean thì đơn giản là một đối tượng được khởi tạo, phân phát và được quản lý bởi IoC container. Sự phụ thuộc giữa chúng được phản ánh trong configuration metadata được sử dụng bởi container.
Giao tiếp org.springframework.beans.factory.BeanFactory là IoC container chịu trách nhiệm chứa, khởi tạo, quản lý và móc nối sự phụ thuộc giữa các bean.
Một cài đặt (kế thừa) của BeanFactory là XmlBeanFactory - nhận XML configuration metadata và sử dụng nó để cấu hình cho ứng dụng.
Configuration metadata có định dạng XML (hoặc properties), được sử dụng để viết các bean definitions cho các bean mà bạn muốn IoC container quản lý.
Ở mức cơ bản nhất thì cấu hình IoC container phải chứa ít nhất một bean mà container đó phải quản lý. Khi sử dụng XML-based configuration metadata, các bean này được cấu hình như một hoặc nhiều element bên trong element. Các bean này tương ứng với các đối tượng được tạo trong ứng dụng.

Ví dụ về cấu trúc cơ bản của XML-based configuration metadata:






xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
















1.2. Khởi tạo một container:

Khởi tạo IoC container thì rất dễ, sau đây là một ví dụ về cách khởi tạo nó:

Resource resource = new FileSystemResource("beans.xml");

BeanFactory factory = new XmlBeanFactory(resource);

hoặc

ClassPathResource resource = new ClassPathResource("beans.xml");



BeanFactory factory = new XmlBeanFactory(resource);

hoặc


ApplicationContext context = new ClassPathXmlApplicationContext(

new String[] {"applicationContext.xml", "applicationContext-part2.xml"});

// of course, an ApplicationContext is just a BeanFactory

BeanFactory factory = (BeanFactory) context;


1.3. Dependecy Injection (DI):
Là các đối tượng định nghĩa sự phụ thuộc của chúng thông qua tham số của phương thức khởi tạo (constructor) hoặc các thuộc tính được thiết lập trên thể hiện (instance) sau khi nó được khởi tạo hoặc trả về từ phương thức factory. Sau đó là công việc của container, nó sẽ đảo ngược sự phụ thuộc đó khi nó tạo bean. Do đó nó có tên là Inversion of Control (IoC).
Có hai biến thể chính của DI là: Setter Injection và Constructor Injection.

a) Setter Injection:

Được nhận ra bởi phương thức setter trên bean sau khi triệu gọi phương thức khởi tạo không tham số hoặc phương thức static factory không tham số để khởi tạo bean.


b) Constuctor injection:
Được nhận ra bằng cách triệu gọi một phương thức khởi tạo với một số tham số.

Một biến thể khác thay thế cho constructor là sử dụng phương thức static factory để trả về thể hiện của đối tượng.


Ví dụ:


factory-method="createInstance">












public class ExampleBean {

// a private constructor

private ExampleBean(…) {

// ...


}
// a static factory method; the arguments to this method can be

// considered the dependencies of the bean that is returned,

// regardless of how those arguments are actually used.

public static ExampleBean createInstance(AnotherBean anotherBean,

YetAnotherBean yetAnotherBean, int i) {

ExampleBean eb = new ExampleBean(…);

// some other operations

// ...


return eb;

}

}


Các tham số của phương thức static factory được cung cấp thông qua constructor-arg element. Một điều quan trọng là loại của lớp được trả về bởi phương thức factory thì không cùng loại với lớp chứa phương thức static factory, mặc dù trong ví dụ này thì cùng loại.
1.4. ApplicationContext:
Giao tiếp ApplicationContext kế thừa một giao tiếp gọi là MessageSource và do đó nó cung cấp thêm chức năng messaging (đa ngôn ngữ).
Hiện tại thì Spring cung cấp hai cài đặt của MessageSource là ResourceBundleMessageSource và StaticMessageSource. StaticMessageSource thì cứng, nhưng là cách tốt để thêm các message vào source. ResourceBundleMessageSource thì hấp dẫn hơn, sau đây là ví dụ sử dụng nó:




class="org.springframework.context.support.ResourceBundleMessageSource">






format

exceptions

windows









Giả sử bạn có 3 resource bundle được định nghĩa trong classpath gọi là format, exceptions và windows. Và nội dung như sau:
# in 'format.properties'

message=Alligators rock!


# in 'exceptions.properties'

argument.required=The '{0}' argument is required.


Bây giờ bạn có thể lấy message từ các file trên như sau:
public static void main(String[] args) {

MessageSource resources = new ClassPathXmlApplicationContext(

"beans.xml");

String message = resources.getMessage("message", null, "Default", null);

System.out.println(message);

}
Ghi chú: Do ApplicationContext kế thừa từ MessageSource nên bạn có thể ép kiểu của nó thành MessageSource.


Và kết quả từ chương trình sẽ là...Alligators rock!
Tóm lại, MessageSource được định nghĩa trong file gọi là beans.xml. Bean "messageSource" tham chiếu đến một số resource bundle thông qua thuộc tính basenames, ở đây có 3 file được chuyển vào list của thuộc tính basename: format.properties, exceptions.properties và windows.properties.
Với internationlization (i18n), Spring cài đặt theo nguyên tắc như ResourceBundle của JDK. Với messageSource ở trên, nếu muốn chuyển sang locale British (en_GB), bạn phải tạo các file gọi là format_en_GB.properties, exceptions_en_GB.properties và windows_en_GB.properties.

# in 'exceptions_en_GB.properties'

argument.required=Ebagum lad, the '{0}' argument is required, I say, required.
public static void main(final String[] args) {

MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");

String message = resources.getMessage("argument.required", new Object[] { "userDao" }, "Required", Locale.UK);

System.out.println(message);

}
Kết quả từ chương trình trên sẽ là....Ebagum lad, the 'userDao' argument is required, I say, required.
1.4.1. Truyền sự kiện đến bean cài đặt giao tiếp ApplicationListener:
Điều khiển sự kiện trong ApplicationContext được cung cấp thông qua lớp ApplicationEvent và giao tiếp ApplicationListener. Nếu một bean cài đặt giao tiếp ApplicationListener, thì bean đó sẽ được thông báo.
Spring cung cấp 3 sự kiện:


  1. ContextRefreshedEvent: Sự kiện được cho biết khi ApplicationContext được khởi tạo hoặc refresh. Khởi tạo nghĩa là tất cả bean được load, singleton được khởi tạo lại và ApplicationContext sẵn sàng để sử dụng.

  2. ContextClosedEvent: Sự kiện được cho biết khi ApplicationContext bị đóng, sử dụng phương thức close() trên ApplicationContext. Đóng có nghĩa là singleton bean bị hủy.

  3. RequestHandledEvent: Sự kiện được cho biết khi Http request hoàn tất. Được sử dụng cho ứng dụng web có sử dụng DispatcherServlet của Spring.


1.4.2. Resource
Resource trong Spring được sử dụng để truy cập các resource ở mức thấp.Có một vài cài đặt Resource: UrlResource (truy cập các đối tượng thông qua URL, file, Http target, Ftp target..), ClassPathResource (truy cập resource từ classpath), FileSystemResource (resource từ hệ thống file), ServletContextResource (truy cập resource từ đường dẫn tương đối căn cứ theo thư mục root của ứng dụng web), InputStreamResource (load nội dung từ byte array), ByteArrayResource (được cài đặt bởi bất kỳ đối tượng nào có thể trả về các thể hiện Resource).
1.4.3. ApplicationContext và Resource paths:
Xây dựng application context: phương thức khởi tạo của application context nhận vào một string hoặc một mảng string chứa đường dẫn của resource như XML file (định nghĩa context).
Nếu vị trí của đường dẫn không có prefix, thì loại Resource xây dựng từ đường dẫn sẽ được sử dụng để load bean definition, phụ thuộc vào application context.
Ví dụ tạo một ClassPathXmlApplicationContext như sau:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");

=> bean definition sẽ được load từ classpath do đó ClassPathResource sẽ được sử dụng. Nhưng nếu bạn tạo:


ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");

=> bean definition sẽ được load từ hệ thống file, trong trường hợp này liên quan đến thư mục làm việc hiện hành.


Ghi chú: Sử dụng prefix classpath hoặc prefix URL trong đường dẫn sẽ đè lên loại Resource mặc định được tạo để load definition. Vì thế FileSystemXmlApplicationContext.......

ApplicationContext ctx =

new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");

....sẽ load bean definition từ classpath. Tuy nhiên, nó vẫn là FileSystemXmlApplicationContext.


1.4.4. Validation, Data-biding
Sử dụng để validate các đối tượng. Giao tiếp Validator sử dụng một đối tượng Errors trong khi validating, validator sẽ báo cáo các validation fail cho đối tượng này.

Chúng ta hãy xem một lớp sau:

public class Person {

private String name;


private int age;

// the usual getters and setters...

}
Bây giờ chúng ta sẽ cung cấp hàm validation cho lớp này bằng cách cài đặt 2 phương thức của giao tiếp org.springframework.validation.Validator:
public class PersonValidator implements Validator {

/**


* This Validator validates just Person instances

*/

public boolean supports(Class clazz) {



return Person.class.equals(clazz);

}
public void validate(Object obj, Errors e) {

ValidationUtils.rejectIfEmpty(e, "name", "name.empty");

Person p = (Person) obj;

if (p.getAge() < 0) {

e.rejectValue("age", "negativevalue");

} else if (p.getAge() > 110) {

e.rejectValue("age", "too.darn.old");



}

}

}


Phương thức static rejectIfEmpty() của lớp ValidationUtils được sử dụng để bác bỏ thuộc tính "name" nếu nó là chuỗi rỗng hoặc null. Trong Spring Web MVC bạn có thể sử dụng thẻ để đưa ra error message.
2. Aspect Oriented Programming with Spring
AOP thì bổ sung cho OOP bằng cách cung cấp cách suy nghĩ khác về cấu trúc của chương trình. AOP cho bạn các lát cắt (aspect). Aspect cho phép module hóa các yêu cầu (concern), ví dụ như transaction management cắt xuyên qua nhiều đối tượng (vì thế các yêu cầu này thường được gọi là yêu cầu đan xen).
Một trong các component của Spring là AOP framework. Trong khi IoC container thì không phù thuộc vào AOP, nghĩa là bạn không cần sử dụng AOP nếu bạn không muốn, AOP bổ sung cho IoC để cung cấp một giải pháp middleware.
AOP được sử dụng trong Spring để:

  • Cung cấp khai báo các service mức enterprise (đặc biệt thay thế cho EJB service). Service quan trọng nhất là declarative transaction management.

  • Cho phép người dùng cài đặt các aspect tùy chọn để bổ sung cho OOP.


Ghi chú: khái niệm annotation

Programmer có thể annotation vào source code dưới hình thức comment. Điều này không ảnh hưởng đến chương trình nhưng nó cho phép người khác biết thêm một vài thông tin khi đọc source code.

Annotation cũng có thể được thêm bởi trình biên dịch hoặc programmer dưới hình thức metadata. Ví dụ: trình biên dịch có thể sử dụng metadata để quyết định cảnh báo gì sẽ phân phát hoặc linker có thể sử dụng metadata để kết nối nhiều object file thành 1 file thực thi.
Sử dụng AOP để module hóa các yêu cầu chính (yêu cầu nghiệp vụ) và bạn sẽ cung cấp các concern này cho nhiều concern khác trong ứng dụng. Logging, security là yêu cầu đan xen tồn tại trong nhiều ứng dụng. Sử dụng AOP, bạn có thể dễ dàng triệu gọi các phương thức mà bạn muốn trong lớp logging trước hay sau mỗi lời gọi phương thức trong ứng dụng.
Điều quan trọng là bạn nên hiểu là AOP để bổ sung cho OOP, hơn là cạnh tranh.
2.1. Các loại AOP:
AOP tĩnh được cung cấp bởi AspectJ - các yêu cầu đan xen được cung cấp đến code vào thời gian biên dịch, và bạn không thể thay đổi nó nếu như bạn không sửa code và biên dịch lại.
Với AOP động như Spring AOP, các yêu cầu đan xen được cung cấp động vào lúc runtime. Điều này cho phép bạn thay đổi các đen xen mà không cần biên dịch lại ứng dụng. Hai loại này bổ sung cho nhau để tạo nên mối kết hợp mạnh mẽ mà bạn có thể sử dụng trong ứng dụng.
2.2. Một số khái niệm của AOP:

  • Joinpoints: Là một điểm được định nghĩa trong chương trình. Joinpoint gồm có: một lời gọi đến một phương thức, khởi tạo lớp, khởi tạo đối tượng. Joinpoint là khái niệm cơ bản của AOP và định nghĩa các point trong ứng dụng để bạn có thể chèn thêm vào nghiệp vụ.

  • Advice: Mã được thực thi ở từng joinpoint được gọi advice. Có nhiều loại advice: before - thực thi trước joinpoint, after - thực thi sau nó.

  • Pointcuts: Là tập hợp các joinpoint mà bạn sử dụng định nghĩa để thực thi advice.

  • Aspects: Mối kết hợp giữa advice và pointcut.

  • Weaving: Tiến trình chèn aspect vào code của ứng dụng ở các điểm thích hợp.

  • Target: Một đối tượng mà luồng thực thi của nó được sửa bởi một vài tiến trình AOP được gọi là target object.

  • Introduction: Đây là tiến trình để bạn có thể sửa cấu trúc của một đối tượng bằng cách giới thiệu thêm một vài phương thức hoặc trường vào nó. Bạn có thể sử dụng introduction để làm cho bất kỳ đối tượng nào cài đặt một giao tiếp xác định mà không cần lớp đó phải cài đặt giao tiếp rõ ràng.


2.3. AOP trong Spring:
Trước khi đào xâu vào thảo luận Spring AOP, chúng ta sẽ xem ví dụ đơn giản sau. Đầu tiên chúng ta tạo một lớp đơn giản xuất ra từ "World", và sau đó sử dụng AOP chuyển một thể hiện vào lớp này vào lúc runtime để in ra từ "Hello World".
public class MessageWriter {

public void writeMessage() {

System.out.print("World");

}

}


Lớp này không có gì đặc biệt, nó chỉ có một phương thức in ra message "World". Chúng ta muốn thêm một vài advice vào lớp này để phương thức writeMessage() in ra message "Hello World".
Để thực hiện được điều này, chúng ta cần thực thi một vài đoạn mã trước phương thức writeMessage() để in ra "Hello", và một vài mã sau phương thức writeMessage() để in "!". Những gì chúng ta cần là một around advice - advice thực thi xung quanh một joinpoint. Trong trường hợp này joinpoint là lời triệu gọi phương thức writeMessage().

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;
public class MessageDecorator implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable {

System.out.println("Hello");

Object rel = invocation.proceed();

System.out.println("!");

return rel;

}
}
Giao tiếp MethodInterceptor là một giao diện chuẩn của AOP Alliance để cài đặt around advice cho joinpoint. Đối tượng MethodInvocation sẽ triệu gọi phương thức được advise, sử dụng đối tượng này chúng ta có thể điều khiển khi nào phương thức này được phép xử lý. Bởi vì đây là around advice, chúng ta cần biểu diễn một vài hành động trước khi phương thức này được triệu gọi và một vài hành động sau khi nó được triệu gọi nhưng trước khi nó trả về. Chúng ta sẽ in ra từ "Hello", triệu gọi phương thức với mội lời gọi là MethodInvocation.proceed(), và sau đó in ra "!".


Bước cuối cùng trong ví dụ này là đan xen các advice MessageDecorator vào code. Để làm điều này, chúng ta tạo một thể hiện của MessageWriter, sau đó tạo proxy của thể hiện này, hướng dẫn proxy factory đan xen advice MessageDecorator:
import org.springframework.aop.framework.ProxyFactory;
public class HelloWorldAOP {

public static void main(String[] args) {

MessageWriter target = new MessageWriter();

ProxyFactory pf = new ProxyFactory();

pf.addAdvice(new MessageDecorator());

pf.setTarget(target);

MessageWriter proxy = (MessageWriter) pf.getProxy();

proxy.writeMessage();

}

}
Phần quan trọng ở đây là chúng ta sử dụng lớp ProxyFactory để tạo proxy cho đối tượng target, đan xen advice vào cùng thời điểm. Chúng ta sẽ chuyển vào một advice MessageDecorator bằng phương thức addAdvice() và xác định target để đan xen bằng cách gọi phương thức setTarget(). Mỗi khi target được thiết lập và một vài advice được thêm vào ProxyFactory, chúng ta sẽ phát sinh proxy với một lời gọi getProxy(). Cuối cùng chúng ta gọi writeMessage() trên đối tượng proxy. Kết quả sẽ là:


Hello World!
Nếu chúng ta gọi phương thức writeMessage() trên đối tượng target thì kết quả chỉ là nội dung của phương thức được triệu gọi. Tuy nhiên, nếu triệu gọi proxy thì code trong MessageDecorartor sẽ được thực thi và nó sẽ tạo kết xuất như mong muốn "Hello World". Từ ví dụ này, bạn có thể thấy rằng lớp advice không phụ thuộc vào Spring hoặc giao tiếp AOP Alliance, hơn nữa bạn còn có thể advice hầu như bất kỳ lớp nào, thậm chí lớp đó được tạo không sử dụng AOP.
2.3.1. Một vài loại advice:

  • Before - org.springframework.aop.MethodBeforeAdvice - Sử dụng before advice, bạn có thể xử lý tùy ý trước khi thực thi joinpoint.

  • After Return - org.springframework.aop.AfterReturningAdvice - After Return advice sẽ được thực thi sau khi triệu gọi phương thức (method invocation) ở joinpoint hoàn tất và trả về giá trị.

  • Around - org.aopalliance.intercept.MethodInterceptor - around advice được mô hình bởi chuẩn AOP Alliance (cung cấp các API để tích hợp các yêu cầu riêng rẽ trên từng module lại với nhau). Advice của bạn được phép thực thi trước và sau method invocation, và bạn có thể điều khiển nơi mà method invocation được phép xử lý.

  • Throws - org.springframework.aop.ThrowsAdvice - ném advice được thực thi sau khi method invocation trả về, để bắt lấy các exception xác định, nhưng chỉ xảy ra nếu invocation đã ném vào exception.

  • Introduction - org.springframework.aop.IntroductionInterceptor - Sử dụng để xác định cài đặt cho các phương thức được giới thiệu bởi advice.


a) Tạo before advice:
Nó là loại advice hữu ích nhất của Spring. Bởi vì nó có thể sửa các tham số được chuyển đến phương thức và có thể ngăn chặn phương thức thực thi bằng cách tạo ra một exception. Sau đây chúng ta sẽ xem một ví dụ đơn giản sử dụng before advice - in ra message chứa tên của phương thức trước khi thực thi phương thức:
import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

import org.springframework.aop.framework.ProxyFactory;
public class SimpleBeforeAdvice implements MethodBeforeAdvice {
public static void main(String[] args) {

ProxyFactory pf = new ProxyFactory();

pf.setTarget(new MessageWriter());

pf.addAdvice(new SimpleBeforeAdvice());

MessageWriter proxy = (MessageWriter) pf.getProxy();

proxy.writeMessage();

}
public void before(Method method, Object[] args, Object target)

throws Throwable {

System.out.println("Method before: " + method.getName());

}
}
Lớp SimpleBeforeAdvice cài đặt 1 phương thức before() của giao tiếp MethodBeforeAdvice, để AOP framework gọi nó trước khi gọi phương thức ở joinpoint. Nhớ rằng, chúng ta sử dụng pointcut mặc định được cung cấp bởi phương thức addAdvice(). Phương thức before() thì được chuyển vào 3 tham số: phương thức được triệu gọi, các tham số được chuyển cho phương thức đó, và một Object là target. Lớp SimpleBeforeAdvice sử dụng tham số Method của phương thức before() để in ra message chứa tên của phương thức được triệu gọi. Chạy ví dụ này sẽ xuất ra như sau:


2007/01/17 13:34:59 org.springframework.aop.framework.DefaultAopProxyFactory

情報: CGLIB2 available: proxyTargetClass feature enabled

2007/01/17 13:35:00 org.springframework.core.CollectionFactory

情報: JDK 1.4+ collections available

Method before: writeMessage

World
Sau đây là một ví dụ security advice đơn giản để giới hạn việc truy cập phương thức trên đối tượng.
Chúng ta sẽ xây dựng before advice kiểm tra thông tin (credentials) của user trước khi cho phép method invocation xử lý. Nếu credentials của user không hợp lệ, một exception sẽ bị ném bởi advice, do đó nó sẽ ngăn không cho phương thức thực thi. Ví dụ này thì đơn giản - nó cho phép user xác nhận với kỳ password nào, và nó chỉ cho phép một user (được code cứng) truy cập vào phương thức secure. Tuy nhiên, nó minh họa cách sử dụng AOP để cài đặt yêu cầu đan xen như security.
Phía dưới là lớp SecureBean sẽ được bảo vệ (secure):
public class SecureBean {

public void writeSecureMessage() {

System.out.println("Every time I learn something new, "

+ "it pushes some old stuff out of my brain");

}
}
Lớp UserInfo để lưu credentials của user:
public class UserInfo {

private String userName;

private String password;

public UserInfo(String username, String passwd) {

this.userName = username;

this.password = passwd;

}
public String getPassword() {

return password;

}
public void setPassword(String password) {

this.password = password;

}
public String getUserName() {

return userName;

}
public void setUserName(String userName) {

this.userName = userName;

}
}
Không có thứ gì đặc biệt trong lớp này, nó chỉ đơn giản giữ dữ liệu của user vì thế chúng ta có thể làm một vài thứ hữu ích với nó. Lớp SecurityManager sau sẽ chịu trách nhiệm xác nhận user và lưu credentials của user để rút trích sau đó.
public class SecurityManager {

private static ThreadLocal threadLocal = new ThreadLocal();


public void login(String userName, String password) {

threadLocal.set(new UserInfo(userName, password));

}
public void logout() {

threadLocal.set(null);

}
public UserInfo getLoggedOnUser() {

return (UserInfo) threadLocal.get();

}

}
Ứng dụng sẽ sử dụng lớp SecurityManager để xác nhận user và sau đó rút trích chi tiết về user đã được xác thực. Ứng dụng xác thực user bằng phương thức login(). Trong ứng dụng thực sự, phương thức login sẽ kiểm tra user từ database hoặc LDAP nhưng ở đây chúng ta giả sử rằng tất cả user đều được xác thực. Phương thức login() tạo một đối tượng UserInfo cho user và lưu nó vào thread hiện hành bằng ThreadLocal. Phương thức logout thiết lập bất kỳ giá trị nào có thể được lưu trong ThreadLocal là null. Cuối cùng, phương thức getLogggedOnUser() sẽ trả về đối tượng UserInfo cho user đã được xác thực. Phương thức này trả về null nếu user không được xác thực.


Để kiểm tra user đã được xác thực hay chưa, để cho phép user truy cập vào phương thức trên SecureBean hay không, chúng ta cần tạo một advice thực thi trước phương thức và kiểm tra đối tượng UserInfo được trả về bởi SecurityManager.getLoggedOnUser(). Mã của advice này như sau:
import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;


public class SecurityAdvice implements MethodBeforeAdvice {
private SecurityManager securityManager;
public SecurityAdvice() {

this.securityManager = new SecurityManager();

}

public void before(Method method, Object[] args, Object target)



throws Throwable {

UserInfo user = securityManager.getLoggedOnUser();

if (null == user) {

System.out.println("No user authenticated");

throw new SecurityException(

"You must login before attempting to invoke the method: "

+ method.getName());

} else if ("robh".equals(user.getUserName())) {

System.out.println("Logged in user is robh - OKAY!");

} else {


System.out.println("Logged in user is " + user.getUserName()

+ " NOT GOOD :(");

throw new SecurityException("User " + user.getUserName()

+ " is not allowed access to method " + method.getName());

}
}
public SecurityManager getSecurityManager() {

return securityManager;

}
public void setSecurityManager(SecurityManager securityManager) {

this.securityManager = securityManager;

}

}
Lớp SecurityAdvice tạo một thể hiện của SecurityManager trong constructor của nó và sau đó lưu thể hiện này vào một trường. Trong phương thức before(), chúng ta thực hiện một kiểm tra đơn giản xem user name của user có phải là robh hông. Nếu phải chúng ta sẽ cho phép user truy cập, ngược lại một exception sẽ được tạo ra. Cũng chú ý là chúng ta kiểm tra đối tượng UserInfo có null hay không để xem user đó có được xác thực hay chưa.


Cuối cùng chúng ta sẽ tạo một ứng dụng sử dụng lớp SecurityAdvice để bảo vệ lớp SecureBean.
import org.springframework.aop.framework.ProxyFactory;
public class SampleSecurity {

public static void main(String[] args) {

SecureBean bean = getSecureBean();

SecurityManager manager = new SecurityManager();

manager.login("robh", "robh");

bean.writeSecureMessage();

manager.logout();

try {


manager.login("trinh", "mathlabo");

bean.writeSecureMessage();

} catch (SecurityException e) {

System.out.println("Exception Caught: " + e.getMessage());

} finally {

manager.logout();

}

}
public static SecureBean getSecureBean() {



ProxyFactory pf = new ProxyFactory();

pf.setTarget(new SecureBean());

pf.addAdvice(new SecurityAdvice());

return (SecureBean) pf.getProxy();

}

}
Trong phương thức getSecureBean(), chúng ta tạo một proxy của lớp SecureBean mà được advise bởi thể hiện của lớp SecurityAdvice. Khi người dùng triệu gọi bất kỳ phương thức nào trên proxy này, thì đầu tiên nó sẽ gửi đến SecurityAdvice để kiểm tra security.



Chạy ví dụ này sẽ cho kết xuất như sau:
2007/01/17 17:41:16 org.springframework.aop.framework.DefaultAopProxyFactory

情報: CGLIB2 available: proxyTargetClass feature enabled

2007/01/17 17:41:17 org.springframework.core.CollectionFactory

情報: JDK 1.4+ collections available

Logged in user is robh - OKAY!

Every time I learn something new, it pushes some old stuff out of my brain

Logged in user is trinh NOT GOOD :(

Exception Caught: User trinh is not allowed access to method writeSecureMessage



  1   2   3


Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2019
được sử dụng cho việc quản lý

    Quê hương