适配器模式源码解析(jdk+spring+springjpa+springmvc)
在JDK里的一些应用,我们打开一个类,XmlAdapter,我们看一下这个名字就可以很充分的说明他是一个Adapter,那这个类是JAXB包下的,public abstract class XmlAdapterpackage 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.xmlorg.springframework.data spring-data-jpa 2.0.9.RELEASE
我们看一下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 getJpaPropertyMap(PersistenceUnitInfo pui) {return getJpaPropertyMap();
}获得提供者的属性,那返回值是一个Map,那下边都是获取提供者的具体信息/*** Return a Map of vendor-specific JPA properties,* typically based on settings in this JpaVendorAdapter instance.* 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 getJpaPropertyMap() {return Collections.emptyMap();}/*** Return the vendor-specific JpaDialect implementation for this* provider, or {@code null} if there is none.*/@Nullabledefault JpaDialect getJpaDialect() {return null;}/*** Return the vendor-specific EntityManagerFactory interface* that the EntityManagerFactory proxy is supposed to implement.* 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.*
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.*
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;@Nullableprivate 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*
NOTE: 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.*/@Nullableprotected 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.* 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.*
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 afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}我们看看下边,上边是一些声明,mappedHandler通过getHandler方法,入参放入processedRequest,通过这里来映射对应的Controller,然后继续往下看,HandlerAdapter,通过getHandlerAdapter这个方法,来获取对应的适配器,下面对request里面进行了一些判断,例如GETHEAD,等等,最下边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.*
A typical implementation:*
{@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的,这里面就会返回falsepublic class SimpleControllerHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return (handler instanceof Controller);}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);}@Overridepublic 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,一些逻辑以及为什么使用适配器模式,也会有所提高的,那希望您们通过这个能够对适配器模式理解透,加深了解,应用自如
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
