Spring 和 AspectJ實現DDD領域驅動設計
DDD能夠幫助我們跟隨業務概念的複雜變化而順利實現軟體開發。無論是Spring或EJB3,下面三層架構:
領域對象
, 映射到關係資料庫的POJO. .數據訪問層
– 典型的無態服務, 包裝(JDBC, Hibernate, JPA, iBatis)等實現於內部,對外提供抽象,比如DAO模式業務服務層
– 另外一種無態服務, 對領域對象進行操作. 一般的設計是引入了一系列領域對象,或返回域對象,執行這些對象的邏輯,然後通過數據訪問層訪問資料庫。服務層是偉大的,因為它專註於業務邏輯,委派技術細節DAO層。用戶界面
– 面向Web留nowadays, typically via web browser. User interface is great because… just the fact it is.
一個領域模型對象內部封裝了狀態,對象的操作是一種有態方式, 對象在行為被調用後導致內部狀態變化,對象的狀態切換是由行為影響導致,這是一種狀態模式。
以Reservation 預約實體為例子,它有下面幾個狀態:
打開今日頭條,查看更多圖片當Reservation預訂時被創建,它有新的狀態(狀態)。一些授權人可以接受預訂,比如暫時保留他們的座位,並發送一封電子郵件,要求他為預訂支付鈔票。然後,當用戶執行貨幣轉移,錢入賬,列印票和第二電子郵件發送到客戶端。
首先Reservation實體是有方法行為的,不是以前的貧血模型,只有屬性的setter/getter方法,這些行為用來切換狀態變化的。
如果我們使用Hibernate持久化Reservation,帶來問題是,Spring如何知道Hibernate管理的那個Reservation實體對象,當Hibernate創建領域對象時,SPring並不知道那個實例,也就無法接管這個領域對象,服務就無法操作到那個Reservation實體。
首先我們使用@Configurable配置領域對象:
@Configurable
@Entity
public class Reservation implements Serializable {
//...
}
這是告訴Spring要管理Reservation對象,而@Entity屬於Hibernate標註,Spring不知道Hibernate何時創建它,這時必須使用AspectJ。配置中加入:
<context:load-time-weaver/>
告訴Spring使用 AspectJ load-time weaving (LTW). 對Hibernate載入的對象進行織入管理。
但是會出現下面錯誤:
java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an "addTransformer(ClassFileTransformer)" method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring"s agent: -javaagent:spring-agent.jar
at org.springframework.context.weaving.DefaultContextLoadTimeWeaver.
setBeanClassLoader(DefaultContextLoadTimeWeaver.java:82)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
initializeBean(AbstractAutowireCapableBeanFactory.java:1322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
… 59 more
失敗了,當應用啟動時,其實它並沒有發現AspectJ agent,然後就告訴我們錯誤,加入 -javaagent:spring-agent.jar 到JVM命令參數,Reservation第一次被載入時,agent會發現@Configurable配置,然後將ApectJ的方面aspect應用於它。
用AspectJ將依賴注入到領域對象
配置:
<context:spring-configured />
<context:component-scan base-package="some.package.domain" />
<context:load-time-weaver aspectj-weaving="on" />
使用Hhibernate的實體類代碼:
package come.package.domain;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
@Configurable
public abstract class Entity<T, ID extends Serializable> {
@Autowired
private SessionFactory sessionFactory;
public T getById(ID id) {
return (T) getSession().get(getClass(), id);
}
public ID save() {
return (ID) getSession().save(this);
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
編譯時JVM參數加入:
-javaagent:~/.m2/repository/org/springframework/spring-instrument/3.0.2.RELEASE/spring-instrument-3.0.2.RELEASE.jar
詳細配置見Spring 3 AOP配置
預訂模型
回到預訂模型, 因為這個增強的Reservation是Spring-aware.它不管是由Hibernate或Struts2創建的,這樣,我們可以將依賴注入到領域對象中:
@Configurable
@Entity
public class Reservation implements Serializable {
@PersistenceContext
private transient EntityManager em;
@Transactional
public void persist() {
em.persist(this);
}
//...
}
注意,我們已經將Spring和Hibernate配置無縫地整合在一個領域模型中了。@Entity和@PersistenceContext是Hibernate,@Configurable和@Transactional是Spring的。
你能注入通常依賴dependencies (其他 Spring beans)到你的領域對象.你可以選擇(@Autowire or even 或者 @Resource ,或者手工setting properties.
※HashMap和Hashtable的6個區別
※Selenium python 實現點擊非select/option下的懸浮隱藏文本
TAG:程序員小新人學習 |