項(xiàng)目4說的是適配器,Peter老師也總結(jié)一下Java中的適配器模式。
適配器模式(Adapter Pattern):將一個(gè)接口轉(zhuǎn)換成客戶希望的另一個(gè)接口,使接口不兼容的那些類可以一起工作,其別名為包裝器(Wrapper)。適配器模式既可以作為類結(jié)構(gòu)型模式,也可以作為對(duì)象結(jié)構(gòu)型模式。
在適配器模式中,我們通過增加一個(gè)新的適配器類來解決接口不兼容的問題,使得原本沒有任何關(guān)系的類可以協(xié)同工作。
根據(jù)適配器類與適配者類的關(guān)系不同,適配器模式可分為對(duì)象適配器和類適配器兩種,在對(duì)象適配器模式中,適配器與適配者之間是關(guān)聯(lián)關(guān)系;在類適配器模式中,適配器與適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系。
角色
Target(目標(biāo)抽象類):目標(biāo)抽象類定義客戶所需接口,可以是一個(gè)抽象類或接口,也可以是具體類。
Adapter(適配器類):適配器可以調(diào)用另一個(gè)接口,作為一個(gè)轉(zhuǎn)換器,對(duì)Adaptee和Target進(jìn)行適配,適配器類是適配器模式的核心,在對(duì)象適配器中,它通過繼承Target并關(guān)聯(lián)一個(gè)Adaptee對(duì)象使二者產(chǎn)生聯(lián)系。
Adaptee(適配者類):適配者即被適配的角色,它定義了一個(gè)已經(jīng)存在的接口,這個(gè)接口需要適配,適配者類一般是一個(gè)具體類,包含了客戶希望使用的業(yè)務(wù)方法,在某些情況下可能沒有適配者類的源代碼。
缺省適配器模式(Default Adapter Pattern):當(dāng)不需要實(shí)現(xiàn)一個(gè)接口所提供的所有方法時(shí),可先設(shè)計(jì)一個(gè)抽象類實(shí)現(xiàn)該接口,并為接口中每個(gè)方法提供一個(gè)默認(rèn)實(shí)現(xiàn)(空方法),那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來實(shí)現(xiàn)需求,它適用于不想使用一個(gè)接口中的所有方法的情況,又稱為單接口適配器模式。缺省適配器模式是適配器模式的一種變體,其應(yīng)用也較為廣泛。在JDK類庫的事件處理包java.awt.event中廣泛使用了缺省適配器模式,如WindowAdapter、KeyAdapter、MouseAdapter等。
類適配器
首先有一個(gè)已存在的將被適配的類
public class Adaptee {
public voidadapteeRequest() {
System.out.println("被適配者的方法");
? ? }
}
復(fù)制代碼
定義一個(gè)目標(biāo)接口
public interface Target {
? ? void request();
}
復(fù)制代碼
怎么才可以在目標(biāo)接口中的?request()?調(diào)用?Adaptee?的?adapteeRequest()?方法呢?
如果直接實(shí)現(xiàn)?Target?是不行的
public class ConcreteTarget implements Target {
? ? @Override
public voidrequest() {
System.out.println("concreteTarget目標(biāo)方法");
? ? }
}
復(fù)制代碼
如果通過一個(gè)適配器類,實(shí)現(xiàn)?Target?接口,同時(shí)繼承了?Adaptee?類,然后在實(shí)現(xiàn)的?request()?方法中調(diào)用父類的?adapteeRequest()?即可實(shí)現(xiàn)
public class Adapter extends Adaptee implements Target{
? ? @Override
public voidrequest() {
? ? ? ? //...一些操作...
? ? ? ? super.adapteeRequest();
? ? ? ? //...一些操作...
? ? }
}
復(fù)制代碼
我們來測(cè)試一下
public class Test {
? ? public static void main(String[] args) {
? ? ? ? Target target = new ConcreteTarget();
? ? ? ? target.request();
? ? ? ? Target adapterTarget = new Adapter();
? ? ? ? adapterTarget.request();
? ? }
}
復(fù)制代碼
輸出
concreteTarget目標(biāo)方法
被適配者的方法
復(fù)制代碼
這樣我們即可在新接口?Target?中適配舊的接口或類
對(duì)象適配器
對(duì)象適配器與類適配器不同之處在于,類適配器通過繼承來完成適配,對(duì)象適配器則是通過關(guān)聯(lián)來完成,這里稍微修改一下?Adapter?類即可將轉(zhuǎn)變?yōu)閷?duì)象適配器
public class Adapter implements Target{
? ? // 適配者是對(duì)象適配器的一個(gè)屬性
? ? private Adaptee adaptee = new Adaptee();
? ? @Override
public voidrequest() {
? ? ? ? //...
? ? ? ? adaptee.adapteeRequest();
? ? ? ? //...
? ? }
}
復(fù)制代碼
注意這里的?Adapter?是將?Adaptee?作為一個(gè)成員屬性,而不是繼承它
電壓適配器
再來一個(gè)好理解的例子,我們國(guó)家的民用電都是 220V,日本是 110V,而我們的手機(jī)充電一般需要 5V,這時(shí)候要充電,就需要一個(gè)電壓適配器,將 220V 或者 100V 的輸入電壓變換為 5V 輸出
定義輸出交流電接口,輸出220V交流電類和輸出110V交流電類
public interface AC {
? ? int outputAC();
}
public class AC110 implements AC {
? ? public final int output = 110;
? ? @Override
public intoutputAC() {
returnoutput;
? ? }
}
public class AC220 implements AC {
? ? public final int output = 220;
? ? @Override
public intoutputAC() {
returnoutput;
? ? }
}
復(fù)制代碼
適配器接口,其中?support()?方法用于檢查輸入的電壓是否與適配器匹配,outputDC5V()?方法則用于將輸入的電壓變換為 5V 后輸出
public interface DC5Adapter {
? ? boolean support(AC ac);
? ? int outputDC5V(AC ac);
}
復(fù)制代碼
實(shí)現(xiàn)中國(guó)變壓適配器和日本變壓適配器
public class ChinaPowerAdapter implements DC5Adapter {
? ? public static final int voltage = 220;
? ? @Override
? ? public boolean support(AC ac) {
return(voltage == ac.outputAC());
? ? }
? ? @Override
? ? public int outputDC5V(AC ac) {
? ? ? ? int adapterInput = ac.outputAC();
? ? ? ? //變壓器...
? ? ? ? int adapterOutput = adapterInput / 44;
System.out.println("使用ChinaPowerAdapter變壓適配器,輸入AC:"+ adapterInput +"V"+",輸出DC:"+ adapterOutput +"V");
returnadapterOutput;
? ? }
}
public class JapanPowerAdapter implements DC5Adapter {
? ? public static final int voltage = 110;
? ? @Override
? ? public boolean support(AC ac) {
return(voltage == ac.outputAC());
? ? }
? ? @Override
? ? public int outputDC5V(AC ac) {
? ? ? ? int adapterInput = ac.outputAC();
? ? ? ? //變壓器...
? ? ? ? int adapterOutput = adapterInput / 22;
System.out.println("使用JapanPowerAdapter變壓適配器,輸入AC:"+ adapterInput +"V"+",輸出DC:"+ adapterOutput +"V");
returnadapterOutput;
? ? }
}
復(fù)制代碼
測(cè)試,準(zhǔn)備中國(guó)變壓適配器和日本變壓適配器各一個(gè),定義一個(gè)方法可以根據(jù)電壓找到合適的變壓器,然后進(jìn)行測(cè)試
public class Test {
? ? private List<DC5Adapter> adapters = new LinkedList<DC5Adapter>();
publicTest() {
? ? ? ? this.adapters.add(new ChinaPowerAdapter());
? ? ? ? this.adapters.add(new JapanPowerAdapter());
? ? }
? ? // 根據(jù)電壓找合適的變壓器
? ? public DC5Adapter getPowerAdapter(AC ac) {
? ? ? ? DC5Adapter adapter = null;
for(DC5Adapter ad : this.adapters) {
if(ad.support(ac)) {
? ? ? ? ? ? ? ? adapter = ad;
break;
? ? ? ? ? ? }
? ? ? ? }
if(adapter == null){
throw new? IllegalArgumentException("沒有找到合適的變壓適配器");
? ? ? ? }
returnadapter;
? ? }
? ? public static void main(String[] args) {
Testtest= new Test();
? ? ? ? AC chinaAC = new AC220();
? ? ? ? DC5Adapter adapter = test.getPowerAdapter(chinaAC);
? ? ? ? adapter.outputDC5V(chinaAC);
? ? ? ? // 去日本旅游,電壓是 110V
? ? ? ? AC japanAC = new AC110();
? ? ? ? adapter = test.getPowerAdapter(japanAC);
? ? ? ? adapter.outputDC5V(japanAC);
? ? }
}
復(fù)制代碼
輸出
使用ChinaPowerAdapter變壓適配器,輸入AC:220V,輸出DC:5V
使用JapanPowerAdapter變壓適配器,輸入AC:110V,輸出DC:5V
復(fù)制代碼
主要優(yōu)點(diǎn):
將目標(biāo)類和適配者類解耦,通過引入一個(gè)適配器類來重用現(xiàn)有的適配者類,無須修改原有結(jié)構(gòu)。
增加了類的透明性和復(fù)用性,將具體的業(yè)務(wù)實(shí)現(xiàn)過程封裝在適配者類中,對(duì)于客戶端類而言是透明的,而且提高了適配者的復(fù)用性,同一個(gè)適配者類可以在多個(gè)不同的系統(tǒng)中復(fù)用。
靈活性和擴(kuò)展性都非常好,通過使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器類,完全符合“開閉原則”。
具體來說,類適配器模式還有如下優(yōu)點(diǎn):
由于適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強(qiáng)。
對(duì)象適配器模式還有如下優(yōu)點(diǎn):
一個(gè)對(duì)象適配器可以把多個(gè)不同的適配者適配到同一個(gè)目標(biāo);
可以適配一個(gè)適配者的子類,由于適配器和適配者之間是關(guān)聯(lián)關(guān)系,根據(jù)“里氏代換原則”,適配者的子類也可通過該適配器進(jìn)行適配。
類適配器模式的缺點(diǎn)如下:
對(duì)于Java、C#等不支持多重類繼承的語言,一次最多只能適配一個(gè)適配者類,不能同時(shí)適配多個(gè)適配者;
適配者類不能為最終類,如在Java中不能為final類,C#中不能為sealed類;
在Java、C#等語言中,類適配器模式中的目標(biāo)抽象類只能為接口,不能為類,其使用有一定的局限性。
對(duì)象適配器模式的缺點(diǎn)如下:
與類適配器模式相比,要在適配器中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個(gè)或多個(gè)方法,可以先做一個(gè)適配者類的子類,將適配者類的方法置換掉,然后再把適配者類的子類當(dāng)做真正的適配者進(jìn)行適配,實(shí)現(xiàn)過程較為復(fù)雜。
適用場(chǎng)景:
系統(tǒng)需要使用一些現(xiàn)有的類,而這些類的接口(如方法名)不符合系統(tǒng)的需要,甚至沒有這些類的源代碼。
想創(chuàng)建一個(gè)可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作。
spring AOP中的適配器模式
在Spring的Aop中,使用的?Advice(通知)?來增強(qiáng)被代理類的功能。
Advice的類型有:MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
在每個(gè)類型?Advice?都有對(duì)應(yīng)的攔截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
Spring需要將每個(gè)?Advice?都封裝成對(duì)應(yīng)的攔截器類型,返回給容器,所以需要使用適配器模式對(duì)?Advice?進(jìn)行轉(zhuǎn)換
三個(gè)適配者類 Adaptee 如下:
public interface MethodBeforeAdvice extends BeforeAdvice {
? ? void before(Method var1, Object[] var2, @Nullable Object var3) throws Throwable;
}
public interface AfterReturningAdvice extends AfterAdvice {
? ? void afterReturning(@Nullable Object var1, Method var2, Object[] var3, @Nullable Object var4) throws Throwable;
}
public interface ThrowsAdvice extends AfterAdvice {
}
復(fù)制代碼
目標(biāo)接口 Target,有兩個(gè)方法,一個(gè)判斷?Advice?類型是否匹配,一個(gè)是工廠方法,創(chuàng)建對(duì)應(yīng)類型的?Advice?對(duì)應(yīng)的攔截器
public interface AdvisorAdapter {
? ? boolean supportsAdvice(Advice var1);
? ? MethodInterceptor getInterceptor(Advisor var1);
}
復(fù)制代碼
三個(gè)適配器類 Adapter 分別如下,注意其中的 Advice、Adapter、Interceptor之間的對(duì)應(yīng)關(guān)系
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return(advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
returnnew MethodBeforeAdviceInterceptor(advice);
}
}
@SuppressWarnings("serial")
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return(advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
returnnew AfterReturningAdviceInterceptor(advice);
}
}
class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return(advice instanceof ThrowsAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
returnnew ThrowsAdviceInterceptor(advisor.getAdvice());
}
}
復(fù)制代碼
客戶端 DefaultAdvisorAdapterRegistry
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
? ? private final List<AdvisorAdapter> adapters = new ArrayList(3);
publicDefaultAdvisorAdapterRegistry() {
? ? ? ? // 這里注冊(cè)了適配器
? ? ? ? this.registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
? ? ? ? this.registerAdvisorAdapter(new AfterReturningAdviceAdapter());
? ? ? ? this.registerAdvisorAdapter(new ThrowsAdviceAdapter());
? ? }
? ? public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
? ? ? ? List<MethodInterceptor> interceptors = new ArrayList(3);
? ? ? ? Advice advice = advisor.getAdvice();
if(advice instanceof MethodInterceptor) {
? ? ? ? ? ? interceptors.add((MethodInterceptor)advice);
? ? ? ? }
? ? ? ? Iterator var4 = this.adapters.iterator();
while(var4.hasNext()) {
? ? ? ? ? ? AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
if(adapter.supportsAdvice(advice)) {? // 這里調(diào)用適配器方法
? ? ? ? ? ? ? ? interceptors.add(adapter.getInterceptor(advisor));? // 這里調(diào)用適配器方法
? ? ? ? ? ? }
? ? ? ? }
if(interceptors.isEmpty()) {
? ? ? ? ? ? throw new UnknownAdviceTypeException(advisor.getAdvice());
}else{
return(MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
? ? ? ? }
? ? }
? ? // ...省略...
}? ?
復(fù)制代碼
這里看 while 循環(huán)里,逐個(gè)取出注冊(cè)的適配器,調(diào)用?supportsAdvice()?方法來判斷?Advice?對(duì)應(yīng)的類型,然后調(diào)用?getInterceptor()?創(chuàng)建對(duì)應(yīng)類型的攔截器
這里應(yīng)該屬于對(duì)象適配器模式,關(guān)鍵字?instanceof?可看成是?Advice?的方法,不過這里的?Advice?對(duì)象是從外部傳進(jìn)來,而不是成員屬性
spring JPA中的適配器模式
在Spring的ORM包中,對(duì)于JPA的支持也是采用了適配器模式,首先定義了一個(gè)接口的?JpaVendorAdapter,然后不同的持久層框架都實(shí)現(xiàn)此接口。
jpaVendorAdapter:用于設(shè)置實(shí)現(xiàn)廠商JPA實(shí)現(xiàn)的特定屬性,如設(shè)置Hibernate的是否自動(dòng)生成DDL的屬性generateDdl;這些屬性是廠商特定的,因此最好在這里設(shè)置;目前Spring提供?HibernateJpaVendorAdapter、OpenJpaVendorAdapter、EclipseLinkJpaVendorAdapter、TopLinkJpaVendorAdapter?四個(gè)實(shí)現(xiàn)。其中最重要的屬性是 database,用來指定使用的數(shù)據(jù)庫類型,從而能根據(jù)數(shù)據(jù)庫類型來決定比如如何將數(shù)據(jù)庫特定異常轉(zhuǎn)換為Spring的一致性異常,目前支持如下數(shù)據(jù)庫(DB2、DERBY、H2、HSQL、INFORMIX、MYSQL、ORACLE、POSTGRESQL、SQL_SERVER、SYBASE)
public interface JpaVendorAdapter
{
? // 返回一個(gè)具體的持久層提供者
? public abstract PersistenceProvider getPersistenceProvider();
? // 返回持久層提供者的包名
? public abstract String getPersistenceProviderRootPackage();
? // 返回持久層提供者的屬性
? public abstract Map<String, ?> getJpaPropertyMap();
? // 返回JpaDialect
? public abstract JpaDialect getJpaDialect();
? // 返回持久層管理器工廠
? public abstract Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface();
? // 返回持久層管理器
? public abstract Class<? extends EntityManager> getEntityManagerInterface();
? // 自定義回調(diào)方法
? public abstract void postProcessEntityManagerFactory(EntityManagerFactory paramEntityManagerFactory);
}
復(fù)制代碼
我們來看其中一個(gè)適配器實(shí)現(xiàn)類 HibernateJpaVendorAdapter
public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
? ? //設(shè)定持久層提供者
? ? private final PersistenceProvider persistenceProvider;
? ? //設(shè)定持久層方言
? ? private final JpaDialect jpaDialect;
publicHibernateJpaVendorAdapter() {
? ? ? ? this.persistenceProvider = new HibernatePersistence();
? ? ? ? this.jpaDialect = new HibernateJpaDialect();
? ? }
? ? //返回持久層方言
public PersistenceProvidergetPersistenceProvider() {
returnthis.persistenceProvider;
? ? }
? ? //返回持久層提供者
public StringgetPersistenceProviderRootPackage() {
return"org.hibernate";
? ? }
? ? //返回JPA的屬性
public MapgetJpaPropertyMap() {
? ? ? ? Map jpaProperties = new HashMap();
if(getDatabasePlatform() != null) {
jpaProperties.put("hibernate.dialect", getDatabasePlatform());
}elseif(getDatabase() != null) {
? ? ? ? ? ? Class databaseDialectClass = determineDatabaseDialectClass(getDatabase());
if(databaseDialectClass != null) {
jpaProperties.put("hibernate.dialect",
? ? ? ? ? ? ? ? ? ? ? ? databaseDialectClass.getName());
? ? ? ? ? ? }
? ? ? ? }
if(isGenerateDdl()) {
jpaProperties.put("hibernate.hbm2ddl.auto","update");
? ? ? ? }
if(isShowSql()) {
jpaProperties.put("hibernate.show_sql","true");
? ? ? ? }
returnjpaProperties;
? ? }
? ? //設(shè)定數(shù)據(jù)庫
? ? protected Class determineDatabaseDialectClass(Database database)? ?
? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
switch (1.$SwitchMap$org$springframework$orm$jpa$vendor$Database[database.ordinal()])
? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
case1:
returnDB2Dialect.class;
case2:
returnDerbyDialect.class;
case3:
returnH2Dialect.class;
case4:
returnHSQLDialect.class;
case5:
returnInformixDialect.class;
case6:
returnMySQLDialect.class;
case7:
returnOracle9iDialect.class;
case8:
returnPostgreSQLDialect.class;
case9:
returnSQLServerDialect.class;
case10:
returnSybaseDialect.class; }
returnnull;
? ? }
? ? //返回JPA方言
public JpaDialectgetJpaDialect() {
returnthis.jpaDialect;
? ? }
? ? //返回JPA實(shí)體管理器工廠
public ClassgetEntityManagerFactoryInterface() {
returnHibernateEntityManagerFactory.class;
? ? }
? ? //返回JPA實(shí)體管理器
public ClassgetEntityManagerInterface() {
returnHibernateEntityManager.class;
? ? }
}
復(fù)制代碼
配置文件中可以這樣指定
</bean>?
復(fù)制代碼
spring MVC中的適配器模式
Spring MVC中的適配器模式主要用于執(zhí)行目標(biāo)?Controller?中的請(qǐng)求處理方法。
在Spring MVC中,DispatcherServlet?作為用戶,HandlerAdapter?作為期望接口,具體的適配器實(shí)現(xiàn)類用于對(duì)目標(biāo)類進(jìn)行適配,Controller?作為需要適配的類。
為什么要在 Spring MVC 中使用適配器模式?Spring MVC 中的?Controller?種類眾多,不同類型的?Controller?通過不同的方法來對(duì)請(qǐng)求進(jìn)行處理。如果不利用適配器模式的話,DispatcherServlet?直接獲取對(duì)應(yīng)類型的?Controller,需要的自行來判斷,像下面這段代碼一樣:
if(mappedHandler.getHandler() instanceof MultiActionController){
? ((MultiActionController)mappedHandler.getHandler()).xxx?
}elseif(mappedHandler.getHandler() instanceof XXX){
? ? ...?
}elseif(...){
? ...?
}?
復(fù)制代碼
這樣假設(shè)如果我們?cè)黾右粋€(gè)?HardController,就要在代碼中加入一行?if(mappedHandler.getHandler() instanceof HardController),這種形式就使得程序難以維護(hù),也違反了設(shè)計(jì)模式中的開閉原則 – 對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
我們來看看源碼,首先是適配器接口?HandlerAdapter
public interface HandlerAdapter {
? ? boolean supports(Object var1);
? ? ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
? ? long getLastModified(HttpServletRequest var1, Object var2);
}
復(fù)制代碼
現(xiàn)該接口的適配器每一個(gè)?Controller?都有一個(gè)適配器與之對(duì)應(yīng),這樣的話,每自定義一個(gè)?Controller?需要定義一個(gè)實(shí)現(xiàn)?HandlerAdapter?的適配器。
springmvc 中提供的?Controller?實(shí)現(xiàn)類有如下
springmvc 中提供的?HandlerAdapter?實(shí)現(xiàn)類如下
HttpRequestHandlerAdapter?這個(gè)適配器代碼如下
public class HttpRequestHandlerAdapter implements HandlerAdapter {
publicHttpRequestHandlerAdapter() {
? ? }
? ? public boolean supports(Object handler) {
returnhandler instanceof HttpRequestHandler;
? ? }
? ? public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? ((HttpRequestHandler)handler).handleRequest(request, response);
returnnull;
? ? }
? ? public long getLastModified(HttpServletRequest request, Object handler) {
returnhandler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
? ? }
}
復(fù)制代碼
當(dāng)Spring容器啟動(dòng)后,會(huì)將所有定義好的適配器對(duì)象存放在一個(gè)List集合中,當(dāng)一個(gè)請(qǐng)求來臨時(shí),DispatcherServlet?會(huì)通過?handler?的類型找到對(duì)應(yīng)適配器,并將該適配器對(duì)象返回給用戶,然后就可以統(tǒng)一通過適配器的?hanle()?方法來調(diào)用?Controller?中的用于處理請(qǐng)求的方法。
public class DispatcherServlet extends FrameworkServlet {
? ? private List<HandlerAdapter> handlerAdapters;
? ? //初始化handlerAdapters
? ? private void initHandlerAdapters(ApplicationContext context) {
? ? ? ? //..省略...
? ? }
? ? // 遍歷所有的 HandlerAdapters,通過 supports 判斷找到匹配的適配器
? ? protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for(HandlerAdapter ha : this.handlerAdapters) {
if(logger.isTraceEnabled()) {
logger.trace("Testing handler adapter ["+ ha +"]");
}
if(ha.supports(handler)) {
returnha;
}
}
}
// 分發(fā)請(qǐng)求,請(qǐng)求需要找到匹配的適配器來處理
protected voiddoDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
// Determine handlerforthe current request.
mappedHandler = getHandler(processedRequest);
// 確定當(dāng)前請(qǐng)求的匹配的適配器.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
ha.getLastModified(request, mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
? ? }
// ...省略...
}
復(fù)制代碼
通過適配器模式我們將所有的?controller?統(tǒng)一交給?HandlerAdapter?處理,免去了寫大量的?if-else?語句對(duì)?Controller?進(jìn)行判斷,也更利于擴(kuò)展新的?Controller?類型。