spring 2.x 中文

60
Spring Framework 2.0 - An Overview x

Upload: guo-albert

Post on 19-May-2015

2.170 views

Category:

Education


0 download

TRANSCRIPT

Page 1: Spring 2.x 中文

Spring Framework 2.0- An Overview

x

Page 2: Spring 2.x 中文

2

大綱

Spring Framework 簡介

Spring 2.x 新增功能

結語

Page 3: Spring 2.x 中文

3

Spring Framework的誕生

Spring之父 – R.Johnson

畢業於澳洲雪梨大學

擁有音樂學(Musicology)博士的學位

JSR-154(Servlet 2.4)規格委員

公開發表

2002年出版的專書「J2EE Design and Development」第10章以架構描述及範例碼的形式發表。

2003年10月以開放原始碼形式釋出1.0版。

在TSS發表「Introduction to Spring Framework」文章後開始受到Java社群重視。

Page 4: Spring 2.x 中文

4

Spring Framework架構概觀

Page 5: Spring 2.x 中文

5

Spring Framework 的理論基礎

為什麼要了解Spring的理論基礎?

幫助您正確評估是否採用Spring Framework

縮短學習時間

完全發揮Spring Framework 的威力

主要理論基礎

控制權倒置 (Inversion of Control)

依賴性注入 (Dependency Injection)

Page 6: Spring 2.x 中文

6

Template Method

核心概念

主流程寫在父類別

可變的部份挖空變成抽象方法

public abstract class HttpServlet … {

protected service(…) {

..

if(..HTTP Get..) doGet(..);

else if (..HTTP Post..) doPost(..);

..

}

public abstract void doGet(..);

public abstract void doPost(..);

}

?

主流程

可變邏輯

Page 7: Spring 2.x 中文

7

Template Method與Hook Method

Service()

{

if(isHttpGet())

doGet()

else if(isHttpPost())

doPost()

}

HttpServlet

hook method

template method

hook

doGet()

doPost()MyHttpServlet

Page 8: Spring 2.x 中文

8

應用程式框架(Application Framework)

定義

可重用的半成品,客製化後,成為一個可用的系統

功能

提供共同領域的抽象化機制

節省開發時間

使得應用程式整體有一定的架構風格

在Template Method中,我們將主流程封裝在父類別中

內含主流程的父類別就是「框架」

透過繼承,重用主流程的子類就是「元件」,更換不同的子類別,框架就能呈現不同的行為

Page 9: Spring 2.x 中文

9

Inversion Of Control (IoC)

Page 10: Spring 2.x 中文

10

依賴性(Dependency)

當某類別繼承另一類別、實作另一介面或者叫用到其它類別,我們就說此類別依賴 (depends-on)

另一個類別。public class MySessionBean implements javax.ejb.SessionBean {

private javax.ejb.SessionContext ctx;

public void ejbCreate() {}

public void ejbRemove() {}

public void ejbActivate() {}

public void ejbPassivate() {}

public void setSessionContext(SessionContext ctx) {

this.ctx = ctx;

}

…(略)…

}

Page 11: Spring 2.x 中文

11

依賴性對程式碼造成負面的影響

依賴性(Dependency)會對程式碼的可重用性會造成負面影響

依賴性愈低,程式的可重用性愈高。

Liskov代換法則也可以看成是降低依賴性的手法

將Client與實作類別中間用介面隔開,去除了Client及實作類別中間的依賴性

<<create>>public MovieLister () {

movieFinder = new MovieFinderImpl();

}

Page 12: Spring 2.x 中文

12

物件生成控制權的倒置

<<create>>

MovieFinderFactory

public MovieFinder create() {

return new MovieFinderImpl();

}

Page 13: Spring 2.x 中文

13

Dependency Injection

IoC Container

Page 14: Spring 2.x 中文

14

輕量級容器與IoC

輕量級容器實質上是「物件生成」的控制權的倒置

輕量級容器又稱為「IoC Container」

輕量級容器中所指IoC和傳統框架型重用中的IoC意義不同:

框架重用的IoC是「主流程主控權」的倒置

而IoC Container的IoC是「物件生成主控權」的倒置

M.Fowler建議使用依賴注入(Dependency Injection)

來指稱「物件生成主控權」的倒置,以避免概念上的混淆

Page 15: Spring 2.x 中文

15

小結

Template Method

Application Framework

Inversion of Control

Dependency

Dependency Injection

Page 16: Spring 2.x 中文

16

大綱

Spring Framework簡介

Spring 2.0新增功能

Bean容器與Bean設定檔

剖面導向程式設計 (AOP)

永續性支援

Message-Driven POJO

結語

Page 17: Spring 2.x 中文

17

Bean 容器

Bean 設定檔POJO

客戶端

Bean 容器運作模式

Page 18: Spring 2.x 中文

18

Bean設定檔的基本結構

Spring的Bean設定由三個部份組成:

XML宣告區段

標頭宣告區段

Bean宣告區段

DTD宣告方式<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"

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

<beans>

</beans>

Page 19: Spring 2.x 中文

19

(Spring 2.x) XML Schema的宣告方式

<? xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans“

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

xsi:schemaLocation=“

http://www.springframework.org/schema/beans

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

<bean id="…" class="…">

<property name="…" value="…"/>

</bean>

<bean id="…" class="…">

</bean>

</beans>

儘可能採用XML Schema形式的宣告

Page 20: Spring 2.x 中文

20

設定Bean屬性

class ProductViewer {

private Product product;

public void setProduct(Product product) {

this.product = product;

}

}

<bean id="productViewer" class="ProductViewer">

<property name="product">

<ref bean="myProduct"/>

</property>

</bean>

<bean id="myProduct" class="Product">

<property name="productId" value="10001"/>

</bean>

Page 21: Spring 2.x 中文

21

Setter Injection (Spring 2.0)

class ProductViewer {

private Product product;

public void setProduct(Product product) {

this.product = product;

}

}

<bean id="productViewer" class="ProductViewer">

<property name="product“ ref="myProduct“ />

</bean>

<bean id="myProduct" class="Product">

<property name="productId" value="10001"/>

</bean>

Page 22: Spring 2.x 中文

22

(Spring 2.x) p-namespace的簡便語法

<bean id="myProduct" class="Product">

<property name="productId“ value="10001"/>

<property name=“myName" ref=“anotherBean"/>

</bean>

<bean id="myProduct" class="Product"

p:productId="10001"

p:myName-ref=“anotherBean"

/>

在標頭加上「xmlns:p=http://www.springframework.org/schema/p」即可使用 p-namespace的簡便語法

Page 23: Spring 2.x 中文

23

取得Bean實例 (Code)

單一設定檔

ApplicationContext context =

new ClassPathXmlApplicationContext(

“beans-config.xml”

);

Product b = (Product) context.getBean(“productB”);

多設定檔String[] beanConfigs =

new String[]{"bean-config1.xml", "bean-config2.xml"};

ApplicationContext context =

new ClassPathXmlApplicationContext(

beanConfigs );

Page 24: Spring 2.x 中文

24

大綱

Spring Framework簡介

Spring 2.0新增功能

Bean容器與Bean設定檔

剖面導向程式設計 (AOP)

永續性支援

Message-Driven POJO

結語

Page 25: Spring 2.x 中文

25

商務邏輯和橫切面邏輯混雜的問題

系統開發過程中往往必須考量許多和主要業務流程無關的橫切面考量(Cross-Cutting Concerns)

交易(Transaction)

安全性

例外處理

記錄檔

若沒有仔細切分,容易讓程式碼中商務流程和系統考量交雜在一起,造成程式難以維護

Page 26: Spring 2.x 中文

26

將剖面(Aspect)單獨考量

基於重用(Reuse)的原則,可以將這些「橫切面」的處理邏輯抽出來成為一個「Aspect」單獨開發

開發完成後再一次套用在所有具有此需求的商務流程

橫切面考量商務領域考量

Page 27: Spring 2.x 中文

27

Pointcuts、Join Points與Advices

Advices

Pointcuts

Join Points

Page 28: Spring 2.x 中文

28

寫作Advice類別

public class LogBeforeAdvice {

public void before(JoinPoint jointPoint) {

…(要插入的邏輯)

}

}

Page 29: Spring 2.x 中文

29

(Spring 2.0) AOP命名空間的宣告

<? 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:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation=

"http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/

spring-beans-2.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/

spring-aop-2.0.xsd">

</beans>

Page 30: Spring 2.x 中文

30

execution( modifiers-pattern?

ret-type-pattern

declaring-type-pattern?

name-pattern(param-pattern)

throws-pattern? )

(Spring 2.0) AOP宣告

<bean id="logBeforeAdvice"

class="mypackage.LogBeforeAdvice"/>

<bean id="product" class="mypackage.Product"/>

<aop:config>

<aop:aspect id="logging" ref="logBeforeAdvice">

<aop:before

pointcut="execution (* mypackage.Product.*(..))"

method="before"/>

</aop:aspect>

</aop:config>

Page 31: Spring 2.x 中文

31

(Spring 2.0) AOP Annotations

<bean id="logBeforeAdvice"

class="mypackage.LogBeforeAdvice"/>

<bean id="product" class="mypackage.Product"/>

<aop:aspectj-autoproxy/>

Page 32: Spring 2.x 中文

32

(Spring 2.0) 寫作Advice類別

@Aspect

public class LogBeforeAdvice {

@Before("execution(* mypackage.Product.*(..))" )

public void before(JoinPoint jointPoint) {

…(要插入的邏輯)

}

}

Page 33: Spring 2.x 中文

33

大綱

Spring Framework簡介

Spring 2.0新增功能

Bean容器與Bean設定檔

剖面導向程式設計 (AOP)

永續性與交易支援

Message-Driven POJO

結語

Page 34: Spring 2.x 中文

34

(Spring 2.0) 使用tx標籤進行宣告式交易

Transaction

Manager

productDao

<tx:advice>

Transaction Attribute= Require

Isolation Level= Default

execution(* *.ProductDao.*(..))

execution( modifiers-pattern?

ret-type-pattern

declaring-type-pattern?

name-pattern(param-pattern)

throws-pattern? )

Page 35: Spring 2.x 中文

35

使用tx標籤進行宣告式交易

<tx:advice id="txAdvice" transaction-manager="txManager">

<tx:attributes>

<tx:method name="get*" read-only="true" />

<tx:method name="*"

propagation="REQUIRED"

isolation="DEFAULT"/>

</tx:attributes>

</tx:advice>

<aop:config>

<aop:advisor pointcut="execution(* *.ProductDao.*(..))"

advice-ref="txAdvice" />

</aop:config>

Page 36: Spring 2.x 中文

36

(Spring 2.0)

使用@Transactional進行宣告式交易

<tx:annotation-driven transaction-manager="txManager" />

public class ProductDaoJdbcImpl

extends JdbcDaoSupport implements ProductDao

{

@Transactional(readOnly = true)

public List getProducts(){

…(存取資料)

}

@Transactional(readOnly = false,

propagation = Propagation.REQUIRED,

isolation = Isolation.DEFAULT)

public void save(Product product){

…(存取資料)

}

}

// 直接標記在介面的實作成品上

Page 37: Spring 2.x 中文

37

Hibernate與JPA

Hibernate Core

開發人員可以選擇只使用JPA以確保 最 大 的 相 容 性 , 或 者 透 過Hibernate API實作更進階的功能,甚至也可以將二者混合使用 !

Hibernate Annotation (JPA)

Hibernate EntityManager

Java Persistence API Hibernate API

Hibernate Annotation (Hibernate)

Hibernate XML 對映檔

Page 38: Spring 2.x 中文

38SessionFactoryBean

HibernateTemplate

Spring對Hibernate的封裝

Configuration

hibernate.cfg.xml

SessionFactory Session

Criteria Query

persist()

save()

update()

saveOrUpdate()

delete()

Transaction

Page 39: Spring 2.x 中文

39

(Spring 2.0) 使用JPA Annotations

@Entity

@Table(name = "TB_PRODUCT")

public class Product {

@Id

@GeneratedValue(strategy=GenerationType.TABLE)

@Column(name = "id")

private int productId;

@Column(name = "name")

private String name;

@Column(name = "price")

private int price;

…(以上三個私有欄位的getter methods及setter methods)…

}

TB_PRODUCT:

名稱 主鍵 型別

id Yes Integer

name No varchar

price No Integer

Page 40: Spring 2.x 中文

40

Spring-Hibernate-DAO整合策略

HibernateTemplate

HibernateDaoSupport

SessionFactoryBean

ProductDao

ProductDaoHibernateImpl實作(implements) 繼承(extends)

相依性注入

Page 41: Spring 2.x 中文

41

Spring-Hibernate整合

public class ProductDaoHibernateImpl extends HibernateDaoSupport

implements ProductDao {

public void save(Product product)

{

getHibernateTemplate().save(product);

}

public List getProducts() throws DataAccessException

{

return (List) getHibernateTemplate().execute( new HibernateCallback() {

public Object doInHibernate(Session session) throws HibernateException {

Criteria criteria = session.createCriteria(Product.class);

criteria.addOrder(Order.asc("price"));

return criteria.list();

}

});

}// end getProducts

}

Page 42: Spring 2.x 中文

42

SessionFactoryBean (Annotation)

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.

annotation.AnnotationSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="annotatedClasses">

<list>

<value>Product</value>

</list>

</property>

<property name="hibernateProperties">

<value>

hibernate.dialect=org.hibernate.dialect.MySQLDialect

hibernate.show_sql=true

</value>

</property>

</bean>

Page 43: Spring 2.x 中文

43

Spring-Hibernate整合

將SessionFactory注入ProductDaoHibernateImpl

<bean id="productDao“ class="ProductDaoHibernateImpl">

<property name="sessionFactory"

ref="sessionFactory" />

</bean>

ProductDaoHibernateImpl SessionFactoryBean DataSource注入 注入

Page 44: Spring 2.x 中文

44

大綱

Spring Framework簡介

Spring 2.0新增功能

Bean容器與Bean設定檔

剖面導向程式設計 (AOP)

永續性支援

Message-Driven POJO

結語

Page 45: Spring 2.x 中文

45

(Spring 2.0) Message-Driven POJO

public class MyMessageDrivenPojo implements MessageListener

{

public void onMessage(Message message){

… // 處理所收到的處理訊息

}

}

主程式

public static void main(String[] args) {

DefaultMessageListenerContainer container =

(DefaultMessageListenerContainer)

context.getBean("listenerContainer");

container.start();

}

Page 46: Spring 2.x 中文

46

Message-Driven POJO (MDP)

<bean id="myMDP" class="MyMessageDrivenPojo" />

<bean id="listenerContainer“

class="org.springframework.jms.listener.

DefaultMessageListenerContainer">

<property name="concurrentConsumers" value="2" />

<property name="connectionFactory" ref="jmsFactory" />

<property name="destination" ref="destination" />

<property name="messageListener" ref="myMDP" />

</bean>

Page 47: Spring 2.x 中文

47

加入交易支援

<bean id="txManager" class="org.springframework.jms.connection.

JmsTransactionManager">

<property name="connectionFactory" ref="connectionFactory" />

</bean>

<bean id="listenerContainer“ class="org.springframework.jms.listener.

DefaultMessageListenerContainer">

<property name="concurrentConsumers" value="2" />

<property name="connectionFactory" ref="jmsFactory" />

<property name="destination" ref="destination" />

<property name="messageListener" ref="myMDP" />

<property name="transactionManager" ref=“txManager" />

</bean>

Page 48: Spring 2.x 中文

48

結語

Spring 2.0 是一個全方位的應用程式框架,主要功能包含了:

輕量級容器

實現依賴注入(Dependency Injection)及非侵入性(No

intrusive)的框架

提供AOP(Aspect-oriented programming)機制

提供對持久層(Persistence)、交易(Transaction)的支援

提供MVC Web框架的實現

對於其它常用企業服務API提供一致的模型封裝

Page 49: Spring 2.x 中文

49

Backup

Page 50: Spring 2.x 中文

50

小結: Spring Framework的設計理念

透過介面進行系統設計(Programming by interface)

以傳統Java物件為主 (POJO-based Programming)

非侵入性

一致的設定檔格式

Page 51: Spring 2.x 中文

51

依賴注入的型式

三種型式

從setter方法注入資源的Setter Injection

從建構子(Constructor)注入的Constructor Injection

透過介面(Interface)注入的Interface injection

Spring Framework支援Setter Injection與Constructor Injection

透過介面的相依性注入具有較強的侵入性,所以Spring

並未採用。

Page 52: Spring 2.x 中文

52

黏合用程式碼(Glue Code)

黏合用程式碼」所在的類別會依賴IoC Container

IoC Container

MovieServlet MovieService

Page 53: Spring 2.x 中文

53

去除Glue Code

IoC Container

MovieServlet MovieService IoCManagerServlet

Page 54: Spring 2.x 中文

54

AOP觀念與術語

Aspect

代表一個Cross-Cutting Concerns

由Pointcut與Advice二類的元件所組成

Advice是Aspect的「具體實作」

Join Points

Advice在切入商務流程的「點」稱之為Join Point

就實作面來說,就是Advice在應用程式中被執行的時間點

Spring只支援類別方法的Join Points

Spring不支援Field成員的Join Points,Spring設計人員認為支援Field的Join Points會破壞物件的封裝性

Page 55: Spring 2.x 中文

55

AOP觀念與術語(2)

Pointcut

Pointcut用來定義一群Join Points

當呼叫的方法符合Pointcut表示式時,系統會自動將Advice與方法縫合(Weaving)

Page 56: Spring 2.x 中文

56

Hibernate的宣告式交易

一般區域交易

<bean id="txManager"

class="org.springframework.jdbc.datasource.

DataSourceTransactionManager">

<property name="dataSource" ref="myDataSource" />

</bean>

Hibernate宣告式交易

<bean id="txManager"

class="org.springframework.orm.hibernate3.

HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

</bean>

Page 57: Spring 2.x 中文

57

NamedParameterJdbcTemplate

String sql = "INSERT INTO t_user (name,age)

VALUES(:userName, :userAge)";

Map namedParameters = new HashMap();

namedParameters.put("userName", name);

namedParameters.put("userAge", age);

NamedParameterJdbcTemplate jdbcTemplate =

new NamedParameterJdbcTemplate(dataSource);

List rows = jdbcTemplate.queryForList(sql, namedParameters);

Page 58: Spring 2.x 中文

58

SimpleJdbcTemplate

JDK 5.0以上適用,支援泛型

String sql = "SELECT * FROM user WHERE id=?";

ParameterizedRowMapper<User> mapper =

new ParameterizedRowMapper<User>() {

public User mapRow(ResultSet rs, int rowNum)

throws SQLException {

return user;

}

};

SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);

jdbcTemplate.queryForObject(sql, mapper, id);

Page 59: Spring 2.x 中文

59

MessageListenerAdapter

上面例子中的MyMessageDrivenPojo 仍然具有相依性

必須繼承javax.jms.MessageListener介面

MessageListenerAdapter

完全切除MDP與JMS的依賴關係

假設使用者自行定義了訊息的處理介面

將介面傳入Adapter做為建構子的參數

public interface MyMessageHandler {

void processMessage(String message);

}

Public class MyMessageHandlerImpl

implements MyMessageHandler { …}

實作不需要實作MessageListener!

Page 60: Spring 2.x 中文

60

MessageListenerAdapter – 設定檔

<bean id="messageListenerAdapter" class="org.springframework.jms.listener.

adapter.MessageListenerAdapter">

<constructor-arg>

<bean class="MyMessageHandlerImpl"/>

</constructor-arg>

<property name="defaultListenerMethod“ value="processMessage"/>

</bean>

<bean id="listenerContainer“ class="org.springframework.jms.listener.

DefaultMessageListenerContainer">

<property name="concurrentConsumers" value="2" />

<property name="connectionFactory" ref="jmsFactory" />

<property name="destination" ref="destination" />

<property name="messageListener" ref="messageListenerAdapter " />

</bean>