适配器模式源码解析(jdk+spring+springjpa+springmvc)

在JDK里的一些应用,我们打开一个类,XmlAdapter,我们看一下这个名字就可以很充分的说明他是一个Adapter,

那这个类是JAXB包下的,

public abstract class XmlAdapter<ValueType,BoundType>

package javax.xml.bind.annotation.adapters;

在JDK中处理XML序列化和反序列化使用的,那这里面一个构造器

protected XmlAdapter() {}

还有两个方法

public abstract BoundType unmarshal(ValueType v) throws Exception;

public abstract ValueType marshal(BoundType v) throws Exception;

public @interface XmlJavaTypeAdapter 

很明显这个是一个注解,那我们在使用XML序列化的时候,也经常使用XML里面的注解,另外我们看一下他的包,

我们看到annotation下有一个adapters,那这里是一个适配器的注解,我们怎么使用呢,例如我们在做序列化和反序列化的时候,

对于时间类型我们自己可以写一个类,同时继承这个抽象类,然后实现unmarshal这个反序列化方法,同时再实现marshal序列化

方法,我们只要实现自定义的适配器就可以了,那在Spring中使用适配器也使用的非常广泛,那我们先看一下Spring中的使用AOP的

一个案例,打开AdvisorAdapter,我们看到这个包在aop下边

很明显每一个Advisor中的advise都要适配成对应的MethodInterceptor对象,那我们看一下AdvisorAdaptor是一个接口,

我们看一下他的实现,我们就看一下MethodBeforeAdviceAdapter

通过这个名字就可以很明显的看出来

这个类是做什么的,也就是做增强方法,运行之前的Adapter,supportAdvise return什么呢,这个advice是不是MethodBeforeAdvice,

对他的类型进行一个判断,然后看下边getInterceptor,那在Spring的JPA中,也大量的使用了适配器模式,我们可以访问Spring的

官网,https://spring.io/projects/spring-data-jpa,我们把这个jar包拿过来

https://github.com/spring-projects/spring-data-examples/blob/master/jpa/pom.xml

<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-jpa</artifactId>
	<version>2.0.9.RELEASE</version>
</dependency>

我们看一下JpaVendorAdapter,在Spring的ORM中,对于JPA的支持呢,也是采用了适配器的方式,我们看一下,首先JpaVendorAdapter,

是一个接口,我们看一下他的子类也就是他的实现类,有哪些,我们看到有一个抽象的JpaVendorAdapter

还有EclipseLink,还有HibernateJapVendorAdapter,这几个方法可以看一下,里面的英文注释,

/**
 * Return the vendor-specific persistence provider.
 */
PersistenceProvider getPersistenceProvider();

返回一个具体的持久层提供者,下面看这个名字

/**
 * Return the name of the persistence provider's root package
 * (e.g. "oracle.toplink.essentials"). Will be used for
 * excluding provider classes from temporary class overriding.
 * @since 2.5.2
 */
@Nullable
default String getPersistenceProviderRootPackage() {
	return null;
}

RootPackage,很明显获取这个提供者的包名,

default Map<String, ?> getJpaPropertyMap(PersistenceUnitInfo pui) {
	return getJpaPropertyMap();
}

获得提供者的属性,那返回值是一个Map,那下边都是获取提供者的具体信息

	/**
	 * Return a Map of vendor-specific JPA properties,
	 * typically based on settings in this JpaVendorAdapter instance.
	 * <p>Note that there might be further JPA properties defined on the
	 * EntityManagerFactory bean, which might potentially override individual
	 * JPA property values specified here.
	 * @return a Map of JPA properties, as accepted by the standard JPA bootstrap
	 * facilities, or an empty Map if there are no properties to expose
	 * @see javax.persistence.Persistence#createEntityManagerFactory(String, Map)
	 */
	default Map<String, ?> getJpaPropertyMap() {
		return Collections.emptyMap();
	}

	/**
	 * Return the vendor-specific JpaDialect implementation for this
	 * provider, or {@code null} if there is none.
	 */
	@Nullable
	default JpaDialect getJpaDialect() {
		return null;
	}

	/**
	 * Return the vendor-specific EntityManagerFactory interface
	 * that the EntityManagerFactory proxy is supposed to implement.
	 * <p>If the provider does not offer any EntityManagerFactory extensions,
	 * the adapter should simply return the standard
	 * {@link javax.persistence.EntityManagerFactory} class here.
	 * @since 2.5.2
	 */
	default Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() {
		return EntityManagerFactory.class;
	}

	/**
	 * Return the vendor-specific EntityManager interface
	 * that this provider's EntityManagers will implement.
	 * <p>If the provider does not offer any EntityManager extensions,
	 * the adapter should simply return the standard
	 * {@link javax.persistence.EntityManager} class here.
	 */
	default Class<? extends EntityManager> getEntityManagerInterface() {
		return EntityManager.class;
	}

	/**
	 * Optional callback for post-processing the native EntityManagerFactory
	 * before active use.
	 * <p>This can be used for triggering vendor-specific initialization processes.
	 * While this is not expected to be used for most providers, it is included
	 * here as a general extension hook.
	 */
	default void postProcessEntityManagerFactory(EntityManagerFactory emf) {
	}

例如getEntityManagerInterface这个是获取持久层的管理器,那下面我们找一个子类来看一下,他的实现类里面的逻辑,

我们就看一下AbstractJpaVendorAdapter,我们简单看一下,定义了一个数据库

public abstract class AbstractJpaVendorAdapter implements JpaVendorAdapter {

	private Database database = Database.DEFAULT;

	@Nullable
	private String databasePlatform;

	private boolean generateDdl = false;

	private boolean showSql = false;

databasePlatform这个呢是一个数据库的平台,generateDdl是否生成Ddl,是否显示SQL,下面都是dataBase的get/set方法,

	/**
	 * Specify the target database to operate on, as a value of the {@code Database} enum:
	 * DB2, DERBY, H2, HSQL, INFORMIX, MYSQL, ORACLE, POSTGRESQL, SQL_SERVER, SYBASE
	 * <p><b>NOTE:</b> This setting will override your JPA provider's default algorithm.
	 * Custom vendor properties may still fine-tune the database dialect. However,
	 * there may nevertheless be conflicts: For example, specify either this setting
	 * or Hibernate's "hibernate.dialect_resolvers" property, not both.
	 */
	public void setDatabase(Database database) {
		this.database = database;
	}

	/**
	 * Return the target database to operate on.
	 */
	protected Database getDatabase() {
		return this.database;
	}

	/**
	 * Specify the name of the target database to operate on.
	 * The supported values are vendor-dependent platform identifiers.
	 */
	public void setDatabasePlatform(@Nullable String databasePlatform) {
		this.databasePlatform = databasePlatform;
	}

	/**
	 * Return the name of the target database to operate on.
	 */
	@Nullable
	protected String getDatabasePlatform() {
		return this.databasePlatform;
	}
	
那在setDatabase的时候,我们可以看到DB2, DERBY, H2, HSQL, INFORMIX, MYSQL, ORACLE, POSTGRESQL, SQL_SERVER, 

SYBASE支持的数据库类型,DB2, DERBY是一个微型的数据库,H2是一个内存数据库,下面的各种方法,你们有兴趣的自己

可以看一下,非常简单,那对于Eclipse和Hibernate这两个实现类呢,你们可以看一下,和我们现在讲的整个类异曲同工
现在我们再看一下在SpringMVC中,使用的适配器,这里使用的适配器还是非常关键的,

他的包是在package org.springframework.web.servlet;这个包下的,我们可以看到,HandlerAdapter有好几个实现,

包括SimpleControllerHandlerAdapter简单的Controller Handler适配器,还有servlet这个类型的,还有RequestMapping,

还有HttpRequest,还有一个抽象类便于扩展的Adapter,那SpringMVC中的适配器到底解决什么问题呢,我们一起来看看源码,

首先进入我们Spring的前端控制器,DispatcherServlet这个类可以说是SpringMVC的一个核心类,我们可以把这个类理解成

我们适配器中的client,也就是Test类,它是一个上帝视角,主要作用是在于通过处理映射器,也就是HandlerMapping,来找到

对应的Handler,对应的Handler呢就是Controller,我们可以理解成一个Controller,一个Servlet,或者是HttpServletHandler,

都是指Controller,同时执行Controller里面对应的方法,并且返回ModelAndView,那这个核心类里面重点的方法,就是doDispatcher,

	/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = processedRequest != request;

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
	
我们看看下边,上边是一些声明,mappedHandler通过getHandler方法,入参放入processedRequest,通过这里来映射对应的Controller,

然后继续往下看,HandlerAdapter,通过getHandlerAdapter这个方法,来获取对应的适配器,下面对request里面进行了一些判断,例如GET

HEAD,等等,最下边mv,mv是什么类型呢,往上看一下,ModelAndView mv = null;mv是ModelAndView,继续,通过适配器ha的handle方法,

返回对应的ModelAndView对象,那这里面用适配器解决什么问题呢,对于Controller我们可以理解成它是一个被适配者,也就是我们讲的,

220V交流电,那么看一下Controller这个接口,mvc下的Controller接口,我们看一下他的具体实现类,这里面关于Controller还是有很多实现类的,

那因为Controller里面有这么多的实现类,所以调用方式就是确定的,那如果我们直接调用Controller里面的方法,那我们就的判断具体呢

是使用的哪个实现类呢,我们可以通过instanceof来判断,而这里面还会写一些if else这种,如果以后我们自己扩展一个自己类型的Controller,

比如我们实现了Controller这个接口,我们还要修改刚刚说的if else的判断逻辑,本身这样就违背了开闭原则,那在SpringMVC中呢,是如何使用

Adapter模式,解决这个问题呢,这就又回到HandlerAdapter这个对象,Spring本身提供了一个适配器接口,我们看一下他的实现,我们可以认为

这里的实现都是为了实现刚刚Controlle里面的实现类,通过这个适配器,使每一个Controller的实现呢,都能找到对应的适配器实现类,让适配器

执行相应的方法,这样的话我们在扩展Controller的时候呢,只需要增加一个适配器类,就可以完成SpringMVC的扩展了,另外再看一下support这个

方法,这里传入的是一个Object类型的Handler

/**
 * Given a handler instance, return whether or not this {@code HandlerAdapter}
 * can support it. Typical HandlerAdapters will base the decision on the handler
 * type. HandlerAdapters will usually only support one handler type each.
 * <p>A typical implementation:
 * <p>{@code
 * return (handler instanceof MyHandler);
 * }
 * @param handler handler object to check
 * @return whether or not this object can use the given handler
 */
boolean supports(Object handler);

刚刚我们也看了,他具体的实现也是用instanceof判断一下,它是具体的哪一种的Handler,也就是说这个Controller,对于我的Adapter,

如果不支持的话,那他就会返回一个false,很必然的,我们看一下Simple的,这里面就会返回false

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	@Override
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return ((Controller) handler).handleRequest(request, response);
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

告诉它不支持,我们再回到DispatcherServlet核心方法中

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

这里面通过getHandlerAdapter这个方法传入对应的Handler,来获取对应的Adapter,从而使每一个Handler呢,

都会有对应的Adapter,那我们看一下这个方法的实现,这个方法的实现还是比较简单的,

/**
 * Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
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)) {
			return ha;
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

你们可以来看一下,一个循环,进行一个判断的支持,然后把ha他进行返回,刚刚我们说的SimpleControllerHandlerAdapter就是我们

常常说的,最简单的Controller类,一个适配器,SimpleControllerHandlerAdapter,那讲到这里呢,相信你们通过学习适配器模式,

对适配器肯定是加深理解的,另外通过我们对JDK以及呢,Spring开源框架的讲解,相信大家对SpringMVC,处理Controller,

一些逻辑以及为什么使用适配器模式,也会有所提高的,那希望您们通过这个能够对适配器模式理解透,加深了解,应用自如

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值