優(yōu)雅的實(shí)現(xiàn)接口轉(zhuǎn)換——Java 適配器模式詳解

項(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ù)制代碼

適配器模式總結(jié)

主要優(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)的類一起工作。

源碼分析適配器模式的典型應(yīng)用

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?類型。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容