313418006
0480-572472840
导航

「技术条记」 「成都校区」Spring 框架的设计理念与设计模式分析

发布日期:2022-05-04 01:00

本文摘要:Spring 的骨骼架构Spring 总共有十几个组件,可是真正焦点的组件只有几个,下面是 Spring 框架的总体架构图:图 1 .Spring 框架的总体架构图从上图中可以看出 Spring 框架中的焦点组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。没有它们就不行能有 AOP、Web 等上层的特性功效。 下面也将主要从这三个组件入手分析 Spring。

博亚体育

Spring 的骨骼架构Spring 总共有十几个组件,可是真正焦点的组件只有几个,下面是 Spring 框架的总体架构图:图 1 .Spring 框架的总体架构图从上图中可以看出 Spring 框架中的焦点组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。没有它们就不行能有 AOP、Web 等上层的特性功效。

下面也将主要从这三个组件入手分析 Spring。Spring 的设计理念前面先容了 Spring 的三个焦点组件,如果再在它们三其中选出焦点的话,那就非 Beans 组件莫属了,为何这样说,其实 Spring 就是面向 Bean 的编程(BOP,Bean Oriented Programming),Bean 在 Spring 中才是真正的主角。

Bean 在 Spring 中作用就像 Object 对 OOP 的意义一样,没有工具的观点就像没有面向工具编程,Spring 中没有 Bean 也就没有 Spring 存在的意义。就像一次演出舞台都准备好了可是却没有演员一样。为什么要 Bean 这种角色 Bean 或者为何在 Spring 如此重要,这由 Spring 框架的设计目的决议,Spring 为何如此盛行,我们用 Spring 的原因是什么,想想你会发现原来 Spring 解决了一个很是关键的问题他可以让你把工具之间的依赖关系转而用设置文件来治理,也就是他的依赖注入机制。而这个注入关系在一个叫 Ioc 容器中治理,那 Ioc 容器就是被 Bean 包裹的工具。

Spring 正是通过把工具包装在 Bean 中而到达对这些工具的治理以及一些列分外操作的目的。它这种设计谋略完全类似于 Java 实现 OOP 的设计理念,固然了 Java 自己的设计要比 Spring 庞大太多太多,可是都是构建一个数据结构,然后凭据这个数据结构设计他的生存情况,并让它在这个情况中根据一定的纪律在不停的运动,在它们的不停运动中设计一系列与情况或者与其他个体完成信息交流。这样想来我们用到的其他框架都是大慨类似的设计理念。焦点组件如何协同事情前面说 Bean 是 Spring 中关键因素,那 Context 和 Core 又有何作用呢?前面把 Bean 比作一场演出中的演员的话,那 Context 就是这场演出的舞台配景,而 Core 应该就是演出的道具了。

只有他们在一起才气具备演出一场好戏的最基本条件。固然有最基本的条件还不能使这场演出脱颖而出,还要他演出的节目足够的精彩,这些节目就是 Spring 能提供的特色功效了。我们知道 Bean 包装的是 Object,而 Object 一定有数据,如何给这些数据提供生存情况就是 Context 要解决的问题,对 Context 来说他就是要发现每个 Bean 之间的关系,为它们建设这种关系而且要维护好这种关系。所以 Context 就是一个 Bean 关系的荟萃,这个关系荟萃又叫 Ioc 容器,一旦建设起这个 Ioc 容器后 Spring 就可以为你事情了。

那 Core 组件又有什么用武之地呢?其实 Core 就是发现、建设和维护每个 Bean 之间的关系所需要的一些列的工具,从这个角度看来,Core 这个组件叫 Util 更能让你明白。它们之间可以用下图来表现:图 2. 三个组件关系焦点组件详解这里将详细先容每个组件内部类的条理关系,以及它们在运行时的时序顺序。

我们在使用 Spring 是应该注意的地方。Bean 组件前面已经说明晰 Bean 组件对 Spring 的重要性,下面看看 Bean 这个组件式怎么设计的。Bean 组件在 Spring 的 org.springframework.beans 包下。这个包下的所有类主要解决了三件事:Bean 的界说、Bean 的建立以及对 Bean 的剖析。

对 Spring 的使用者来说唯一需要体贴的就是 Bean 的建立,其他两个由 Spring 在内部帮你完成了,对你来说是透明的。Spring Bean 的建立时典型的工厂模式,它的顶级接口是 BeanFactory,下图是这个工厂的继续条理关系:图 4. Bean 工厂的继续关系BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。

可是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,实现了所有的接口。那为何要界说这么多条理的接口呢?查阅这些接口的源码和说明发现,每个接口都有使用的场所,它主要是为了区分在 Spring 内部工具的通报和转化历程中,对工具的数据会见所做的限制。例如 ListableBeanFactory 接口表现这些 Bean 是可列表的,而 HierarchicalBeanFactory 表现的这些 Bean 是有继续关系的,也就是每个 Bean 有可能有父 Bean。

AutowireCapableBeanFactory 接口界说 Bean 的自动装配规则。这四个接口配合界说了 Bean 的荟萃、Bean 之间的关系、以及 Bean 行为。Bean 的界说主要有 BeanDefinition 形貌,如下图说明晰这些类的条理关系:图 5. Bean 界说的类条理关系图Bean 的界说就是完整的形貌了在 Spring 的设置文件中你界说的 节点中所有的信息,包罗种种子节点。

当 Spring 乐成剖析你界说的一个 节点后,在 Spring 的内部就被转化成 BeanDefinition 工具。以后所有的操作都是对这个工具完成的。Bean 的剖析历程很是庞大,功效被分的很细,因为这里需要被扩展的地方许多,必须保证有足够的灵活性,以应对可能的变化。

Bean 的剖析主要就是对 Spring 设置文件的剖析。这个剖析历程主要通过下图中的类完成:图 6. Bean 的剖析类固然另有详细对 tag 的剖析这里并没有列出。

Context 组件Context 在 Spring 的 org.springframework.context 包下,前面已经解说了 Context 组件在 Spring 中的作用,他实际上就是给 Spring 提供一个运行时的情况,用以生存各个工具的状态。下面看一下这个情况是如何构建的。ApplicationContext 是 Context 的顶级父类,他除了能标识一个应用情况的基本信息外,他还继续了五个接口,这五个接口主要是扩展了 Context 的功效。

下面是 Context 的类结构图:图 7. Context 相关的类结构图(检察图 7 的清晰版本。)从上图中可以看出 ApplicationContext 继续了 BeanFactory,这也说明晰 Spring 容器中运行的主体工具是 Bean,另外 ApplicationContext 继续了 ResourceLoader 接口,使得 ApplicationContext 可以会见到任何外部资源,这将在 Core 中详细说明。ApplicationContext 的子类主要包罗两个方面:ConfigurableApplicationContext 表现该 Context 是可修改的,也就是在构建 Context 中用户可以动态添加或修改已有的设置信息,它下面又有多个子类,其中最经常使用的是可更新的 Context,即 AbstractRefreshableApplicationContext 类。

WebApplicationContext 顾名思义,就是为 web 准备的 Context 他可以直接会见到 ServletContext,通常情况下,这个接口使用的少。再往下分就是根据构建 Context 的文件类型,接着就是会见 Context 的方式。这样一级一级组成了完整的 Context 品级条理。

总体来说 ApplicationContext 必须要完成以下几件事:标识一个应用情况 使用 BeanFactory 建立 Bean 工具 生存工具关系表 能够捕捉种种事件Context 作为 Spring 的 Ioc 容器,基本上整合了 Spring 的大部门功效,或者说是大部门功效的基础。Core 组件Core 组件作为 Spring 的焦点组件,他其中包罗了许多的关键类,其中一个重要组成部门就是界说了资源的会见方式。这种把所有资源都抽象成一个接口的方式很值得在以后的设计中拿来学习。

下面就重要看一下这个部门在 Spring 的作用。下图是 Resource 相关的类结构图:图 8. Resource 相关的类结构图(检察图 8 的清晰版本。)从上图可以看出 Resource 接口封装了种种可能的资源类型,也就是对使用者来说屏蔽了文件类型的差别。对资源的提供者来说,如何把资源包装起来交给其他人用这也是一个问题,我们看到 Resource 接口继续了 InputStreamSource 接口,这个接口中有个 getInputStream 方法,返回的是 InputStream 类。

这样所有的资源都被可以通过 InputStream 这个类来获取,所以也屏蔽了资源的提供者。另外另有一个问题就是加载资源的问题,也就是资源的加载者要统一,从上图中可以看出这个任务是由 ResourceLoader 接口完成,他屏蔽了所有的资源加载者的差异,只需要实现这个接口就可以加载所有的资源,他的默认实现是 DefaultResourceLoader。

下面看一下 Context 和 Resource 是如何建设关系的?首先看一下他们的类关系图:图 9. Context 和 Resource 的类关系图从上图可以看出,Context 是把资源的加载、剖析和形貌事情委托给了 ResourcePatternResolver 类来完成,他相当于一个讨论人,他把资源的加载、剖析和资源的界说整合在一起便于其他组件使用。Core 组件中另有许多类似的方式。Ioc 容器如何事情前面先容了 Core 组件、Bean 组件和 Context 组件的结构与相互关系,下面这里从使用者角度看一下他们是如何运行的,以及我们如何让 Spring 完成种种功效,Spring 到底能有那些功效,这些功效是如何得来的,下面先容。如何建立 BeanFactory 工厂正如图 2 形貌的那样,Ioc 容器实际上就是 Context 组件联合其他两个组件配合构建了一个 Bean 关系网,如何构建这个关系网?构建的入口就在 AbstractApplicationContext 类的 refresh 方法中。

这个方法的代码如下:清单 1. AbstractApplicationContext.refresh public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }这个方法就是构建整个 Ioc 容器历程的完整的代码,相识了内里的每一行代码基本上就相识大部门 Spring 的原理和功效了。这段代码主要包罗这样几个步骤:构建 BeanFactory,以便于发生所需的“演员”注册可能感兴趣的事件 建立 Bean 实例工具 触发被监听的事件下面就联合代码分析这几个历程。第二三句就是在建立和设置 BeanFactory。这里是 refresh 也就是刷新设置,前面先容了 Context 有可更新的子类,这里正是实现这个功效,当 BeanFactory 已存在是就更新,如果没有就新建立。

下面是更新 BeanFactory 的方法代码:清单 2. AbstractRefreshableApplicationContext. refreshBeanFactory protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException( "I/O error parsing bean definition source for " + getDisplayName(), ex); } }这个方法实现了 AbstractApplicationContext 的抽象方法 refreshBeanFactory,这段代码清楚的说明晰 BeanFactory 的建立历程。注意 BeanFactory 工具的类型的变化,前面先容了他有许多子类,在什么情况下使用差别的子类这很是关键。BeanFactory 的原始工具是 DefaultListableBeanFactory,这个很是关键,因为他设计到后面临这个工具的多种操作,下面看一下这个类的继续条理类图:图 10. DefaultListableBeanFactory 类继续关系图(检察图 10 的清晰版本。

)从这个图中发现除了 BeanFactory 相关的类外,还发现了与 Bean 的 register 相关。这在 refreshBeanFactory 方法中有一行 loadBeanDefinitions(beanFactory) 将找到谜底,这个方法将开始加载、剖析 Bean 的界说,也就是把用户界说的数据结构转化为 Ioc 容器中的特定数据结构。这个历程可以用下面时序图解释:图 11. 建立 BeanFactory 时序图(检察图 11 的清晰版本。)Bean 的剖析和挂号流程时序图如下:图 12. 剖析和挂号 Bean 工具时序图(检察图 12 的清晰版本。

)建立好 BeanFactory 后,接下去添加一些 Spring 自己需要的一些工具类,这个操作在 AbstractApplicationContext 的 prepareBeanFactory 方法完成。AbstractApplicationContext 中接下来的三行代码对 Spring 的功效扩展性起了至关重要的作用。前两行主要是让你现在可以对已经构建的 BeanFactory 的设置做修改,后面一行就是让你可以对以后再建立 Bean 的实例工具时添加一些自界说的操作。

所以他们都是扩展了 Spring 的功效,所以我们要学习使用 Spring 必须对这一部门搞清楚。其中在 invokeBeanFactoryPostProcessors 方法中主要是获取实现 BeanFactoryPostProcessor 接口的子类。并执行它的 postProcessBeanFactory 方法,这个方法的声明如下:清单 3. BeanFactoryPostProcessor.postProcessBeanFactory void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;它的参数是 beanFactory,说明可以对 beanFactory 做修改,这里注意这个 beanFactory 是 ConfigurableListableBeanFactory 类型的,这也印证了前面先容的差别 BeanFactory 所使用的场所差别,这里只能是可设置的 BeanFactory,防止一些数据被用户随意修改。registerBeanPostProcessors 方法也是可以获取用户界说的实现了 BeanPostProcessor 接口的子类,并执行把它们注册到 BeanFactory 工具中的 beanPostProcessors 变量中。

BeanPostProcessor 中声明晰两个方法:postProcessBeforeInitialization、postProcessAfterInitialization 划分用于在 Bean 工具初始化时执行。可以执行用户自界说的操作。后面的几行代码是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener 的子类。

如何建立 Bean 实例并构建 Bean 的关系网下面就是 Bean 的实例化代码,是从 finishBeanFactoryInitialization 方法开始的。清单 4. AbstractApplicationContext.finishBeanFactoryInitialization protected void finishBeanFactoryInitialization( ConfigurableListableBeanFactory beanFactory) { // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }从上面代码中可以发现 Bean 的实例化是在 BeanFactory 中发生的。preInstantiateSingletons 方法的代码如下:清单 5. DefaultListableBeanFactory.preInstantiateSingletons public void preInstantiateSingletons() throws BeansException { if (this.logger.isInfoEnabled()) { this.logger.info("Pre-instantiating singletons in " + this); } synchronized (this.beanDefinitionMap) { for (String beanName : this.beanDefinitionNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX+ beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged( new PrivilegedAction() { public Boolean run() { return ((SmartFactoryBean) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit(); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } } }这里泛起了一个很是重要的 Bean -- FactoryBean,可以说 Spring 一泰半的扩展的功效都与这个 Bean 有关,这是个特殊的 Bean 是一个工厂 Bean,可以发生 Bean 的 Bean,这里的发生 Bean 是指 Bean 的实例,如果一个类继续 FactoryBean 用户只要实现他的 getObject 方法,就可以自己界说发生实例工具的方法。然而在 Spring 内部这个 Bean 的实例工具是 FactoryBean,通过挪用这个工具的 getObject 方法就能获取用户自界说发生的工具,从而为 Spring 提供了很好的扩展性。

博亚体育

Spring 获取 FactoryBean 自己的工具是在前面加上 & 来完成的。如何建立 Bean 的实例工具以及如何构建 Bean 实例工具之间的关联关系式 Spring 中的一个焦点关键,下面是这个历程的流程图。图 13.Bean 实例建立流程图(检察图 13 的清晰版本。)如果是普通的 Bean 就直接建立他的实例,是通过挪用 getBean 方法。

下面是建立 Bean 实例的时序图:图 14.Bean 实例建立时序图(检察图 14 的清晰版本。)另有一个很是重要的部门就是建设 Bean 工具实例之间的关系,这也是 Spring 框架的焦点竞争力,何时、如何建设他们之间的关系请看下面的时序图:图 15.Bean 工具关系建设(检察图 15 的清晰版本。

)Ioc 容器的扩展点现在另有一个问题就是如何让这些 Bean 工具有一定的扩展性,就是可以加入用户的一些操作。那么有哪些扩展点呢? Spring 又是如何挪用到这些扩展点的?对 Spring 的 Ioc 容器来说,主要有这么几个。

BeanFactoryPostProcessor, BeanPostProcessor。他们划分是在构建 BeanFactory 和构建 Bean 工具时挪用。另有就是 InitializingBean 和 DisposableBean, 他们划分是在 Bean 实例建立和销毁时被挪用。

用户可以实现这些接口中界说的方法,Spring 就会在适当的时候挪用他们。另有一个是 FactoryBean 他是个特殊的 Bean,这个 Bean 可以被用户更多的控制。

这些扩展点通常也是我们使用 Spring 来完成我们特定任务的地方,如何醒目 Spring 就看你有没有掌握好 Spring 有哪些扩展点,而且如何使用他们,要知道如何使用他们就必须相识他们内在的机理。可以用下面一个比喻来解释。我们把 Ioc 容器比作一个箱子,这个箱子里有若干个球的模子,可以用这些模子来造许多种差别的球,另有一个造这些球模的机械,这个机械可以发生球模。

那么他们的对应关系就是:BeanFactory 是谁人造球模的机械,球模就是 Bean,而球模造出来的球就是 Bean 的实例。那前面所说的几个扩展点又在什么地方呢? BeanFactoryPostProcessor 对应到当造球模被造出来时,你将有时机可以对其做出适当的修正,也就是他可以帮你修改球模。而 InitializingBean 和 DisposableBean 是在球模造球的开始和竣事阶段,你可以完成一些预备和扫尾事情。

BeanPostProcessor 就可以让你对球模造出来的球做出适当的修正。最后另有一个 FactoryBean,它可是一个神奇的球模。

这个球模不是预先就定型了,而是由你来给他确定它的形状,既然你可以确定这个球模型的形状,固然他造出来的球肯定就是你想要的球了,这样在这个箱子里你可以发现所有你想要的球。Ioc 容器如作甚我所用前面的先容了 Spring 容器的构建历程,那 Spring 能为我们做什么,Spring 的 Ioc 容器又能做什么呢?我们使用 Spring 必须要首先构建 Ioc 容器,没有它 Spring 无法事情,ApplicatonContext.xml 就是 Ioc 容器的默认设置文件,Spring 的所有特性功效都是基于这个 Ioc 容器事情的,好比后面要先容的 AOP。Ioc 它实际上就是为你构建了一个魔方,Spring 为你搭好了骨骼架构,这个魔方到底能变出什么好的工具出来,这必须要有你的到场。

那我们怎么到场?这就是前面说的要相识 Spring 中有哪些扩展点,我们通过实现那些扩展点来改变 Spring 的通用行为。至于如何实现扩展点来获得我们想要的个性效果,Spring 中有许多例子,其中 AOP 的实现就是 Spring 自己实现了其扩展点来到达了它想要的特性功效,可以拿来参考。Spring 中 AOP 特性详解 动态署理的实现原理要相识 Spring 的 AOP 就必须先相识动态署理的原理,因为 AOP 就是基于动态署理实现的。

动态署理还要从 JDK 自己说起。在 Jdk 的 java.lang.reflect 包下有个 Proxy 类,它正是结构署理类的入口。

这个类的结构入下:图 16. Proxy 类结构从上图发现最后面四个是公有方法。而最后一个方法 newProxyInstance 就是建立署理工具的方法。这个方法的源码如下:清单 6. Proxy. newProxyInstance public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } Class cl = getProxyClass(loader, interfaces); try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }这个方法需要三个参数:ClassLoader,用于加载署理类的 Loader 类,通常这个 Loader 和被署理的类是同一个 Loader 类。Interfaces,是要被署理的那些那些接口。

InvocationHandler,就是用于执行除了被署理接口中方法之外的用户自界说的操作,他也是用户需要署理的最终目的。用户挪用目的方法都被署理到 InvocationHandler 类中界说的唯一方法 invoke 中。

这在后面再详解。下面还是看看 Proxy 如何发生署理类的历程,他结构出来的署理类到底是什么样子?下面揭晓啦。图 17. 建立署理工具时序图其实从上图中可以发现正在结构署理类的是在 ProxyGenerator 的 generateProxyClass 的方法中。

ProxyGenerator 类在 sun.misc 包下,感兴趣的话可以看看他的源码。如果有这样一个接口,如下:清单 7. SimpleProxy 类public interface SimpleProxy { public void simpleMethod1(); public void simpleMethod2(); }署理来生成的类结构如下:清单 8. $Proxy2 类public class $Proxy2 extends java.lang.reflect.Proxy implements SimpleProxy{ java.lang.reflect.Method m0; java.lang.reflect.Method m1; java.lang.reflect.Method m2; java.lang.reflect.Method m3; java.lang.reflect.Method m4; int hashCode(); boolean equals(java.lang.Object); java.lang.String toString(); void simpleMethod1(); void simpleMethod2(); }这个类中的方法内里将会是挪用 InvocationHandler 的 invoke 方法,而每个方法也将对应一个属性变量,这个属性变量 m 也将传给 invoke 方法中的 Method 参数。整个署理就是这样实现的。

Spring AOP 如何实现从前面署理的原理我们知道,署理的目的是挪用目的方法时我们可以转而执行 InvocationHandler 类的 invoke 方法,所以如何在 InvocationHandler 上做文章就是 Spring 实现 Aop 的关键所在。Spring 的 Aop 实现是遵守 Aop 同盟的约定。同时 Spring 又扩展了它,增加了如 Pointcut、Advisor 等一些接口使得越发灵活。

下面是 Jdk 动态署理的类图:图 18. Jdk 动态署理的类图上图清楚的显示了 Spring 引用了 Aop Alliance 界说的接口。临时不讨论 Spring 如何扩展 Aop Alliance,先看看 Spring 如何实现署理类的,要实现署理类在 Spring 的设置文件中通常是这样定一个 Bean 的,如下:清单 9. 设置署理类 Beanorg.springframework.aop.framework.PrototypeTargetTests$TestBean truetestInterceptor testInterceptor2设置上看到要设置被署理的接口,和接口的实现类也就是目的类,以及拦截器也就在执行目的方法之前被挪用,这里 Spring 中界说的种种各样的拦截器,可以选择使用。

下面看看 Spring 如何完成了署理以及是如何挪用拦截器的。前面提到 Spring Aop 也是实现其自身的扩展点来完成这个特性的,从这个署理类可以看出它正是继续了 FactoryBean 的 ProxyFactoryBean,FactoryBean 之所以特别就在于它可以让你自界说工具的建立方法。固然署理工具要通过 Proxy 类来动态生成。

下面是 Spring 建立的署理工具的时序图:图 19.Spring 署理工具的发生Spring 建立了署理工具后,当你挪用目的工具上的方法时,将都市被署理到 InvocationHandler 类的 invoke 方法中执行,这在前面已经解释。在这里 JdkDynamicAopProxy 类实现了 InvocationHandler 接口。下面再看看 Spring 是如何挪用拦截器的,下面是这个历程的时序图:图 20.Spring 挪用拦截器以上所说的都是 Jdk 动态署理,Spring 还支持一种 CGLIB 类署理,感兴趣自己看吧。Spring 中设计模式分析Spring 中使用的设计模式也许多,好比工厂模式、单例模式、模版模式等,在《 Webx 框架的系统架构与设计模式》、《 Tomcat 的系统架构与模式设计分析》已经有先容,这里就不赘述了。

这里主要先容署理模式和计谋模式。署理模式 署理模式原理署理模式就是给某一个工具建立一个署理工具,而由这个署理工具控制对原工具的引用,而建立这个署理工具就是可以在挪用原工具时增加一些分外的操作。下面是署理模式的结构:图 21. 署理模式的结构Subject:抽象主题,它是署理工具的真实工具要实现的接口,固然这可以由多个接口组成。ProxySubject:署理类除了实现抽象主题界说的接口外,还必须持有所署理工具的引用RealSubject:被署理的类,是目的工具。

Spring 中如何实现署理模式Spring Aop 中 Jdk 动态署理就是使用署理模式技术实现的。在 Spring 中除了实现被署理工具的接口外,还会有 org.springframework.aop.SpringProxy 和 org.springframework.aop.framework.Advised 两个接口。Spring 中使用署理模式的结构图如下:图 22. Spring 中使用署理模式的结构图$Proxy 就是建立的署理工具,而 Subject 是抽象主题,署理工具是通过 InvocationHandler 来持有对目的工具的引用的。Spring 中一个真实的署理工具结构如下:清单 10 署理工具 $Proxy4 public class $Proxy4 extends java.lang.reflect.Proxy implements org.springframework.aop.framework.PrototypeTargetTests$TestBean org.springframework.aop.SpringProxy org.springframework.aop.framework.Advised { java.lang.reflect.Method m16; java.lang.reflect.Method m9; java.lang.reflect.Method m25; java.lang.reflect.Method m5; java.lang.reflect.Method m2; java.lang.reflect.Method m23; java.lang.reflect.Method m18; java.lang.reflect.Method m26; java.lang.reflect.Method m6; java.lang.reflect.Method m28; java.lang.reflect.Method m14; java.lang.reflect.Method m12; java.lang.reflect.Method m27; java.lang.reflect.Method m11; java.lang.reflect.Method m22; java.lang.reflect.Method m3; java.lang.reflect.Method m8; java.lang.reflect.Method m4; java.lang.reflect.Method m19; java.lang.reflect.Method m7; java.lang.reflect.Method m15; java.lang.reflect.Method m20; java.lang.reflect.Method m10; java.lang.reflect.Method m1; java.lang.reflect.Method m17; java.lang.reflect.Method m21; java.lang.reflect.Method m0; java.lang.reflect.Method m13; java.lang.reflect.Method m24; int hashCode(); int indexOf(org.springframework.aop.Advisor); int indexOf(org.aopalliance.aop.Advice); boolean equals(java.lang.Object); java.lang.String toString(); void sayhello(); void doSomething(); void doSomething2(); java.lang.Class getProxiedInterfaces(); java.lang.Class getTargetClass(); boolean isProxyTargetClass(); org.springframework.aop.Advisor; getAdvisors(); void addAdvisor(int, org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException; void addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException; void setTargetSource(org.springframework.aop.TargetSource); org.springframework.aop.TargetSource getTargetSource(); void setPreFiltered(boolean); boolean isPreFiltered(); boolean isInterfaceProxied(java.lang.Class); boolean removeAdvisor(org.springframework.aop.Advisor); void removeAdvisor(int)throws org.springframework.aop.framework.AopConfigException; boolean replaceAdvisor(org.springframework.aop.Advisor, org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException; void addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException; void addAdvice(int, org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException; boolean removeAdvice(org.aopalliance.aop.Advice); java.lang.String toProxyConfigString(); boolean isFrozen(); void setExposeProxy(boolean); boolean isExposeProxy(); }计谋模式 计谋模式原理计谋模式顾名思义就是做某事的计谋,这在编程上通常是指完成某个操作可能有多种方法,这些方法各有千秋,可能有差别的适应的场所,然而这些操作方法都有可能用到。

各一个操作方法都看成一个实现计谋,使用者可能凭据需要选择合适的计谋。下面是计谋模式的结构:图 23. 计谋模式的结构Context:使用差别计谋的情况,它可以凭据自身的条件选择差别的计谋实现类来完成所要的操作。它持有一个计谋实例的引用。建立详细计谋工具的方法也可以由他完成。

Strategy:抽象计谋,界说每个计谋都要实现的计谋方法ConcreteStrategy:详细计谋实现类,实现抽象计谋中界说的计谋方法Spring 中计谋模式的实现Spring 中计谋模式使用有多个地方,如 Bean 界说工具的建立以及署理工具的建立等。这里主要看一下署理工具建立的计谋模式的实现。前面已经相识 Spring 的署理方式有两个 Jdk 动态署理和 CGLIB 署理。

这两个署理方式的使用正是使用了计谋模式。它的结构图如下所示:图 24. Spring 中计谋模式结构图在上面结构图中与尺度的计谋模式结构稍微有点差别,这里抽象计谋是 AopProxy 接口,Cglib2AopProxy 和 JdkDynamicAopProxy 划分代表两种计谋的实现方式,ProxyFactoryBean 就是代表 Context 角色,它凭据条件选择使用 Jdk 署理方式还是 CGLIB 方式,而另外三个类主要是来卖力建立详细计谋工具,ProxyFactoryBean 是通过依赖的方法来关联详细计谋工具的,它是通过挪用计谋工具的 getProxy(ClassLoader classLoader) 方法来完成操作。

竣事语本文通过从 Spring 的几个焦点组件入手,试图找出构建 Spring 框架的骨骼架构,进而分析 Spring 在设计时的一些设计理念,是否从中找出一些好的设计思想,对我们以后法式设计能提供一些思路。接着再详细分析了 Spring 中是如何实现这些理念的,以及在设计模式上是如何使用的。

通太过析 Spring 给我一个很大的启示就是这套设计理念其实对我们有很强的借鉴意义,它通过抽象庞大多变的工具,进一步做规范,然后凭据它界说的这套规范设计出一个容器,容器中构建它们的庞大关系,其实现在有许多情况都可以用这种类似的处置惩罚方法。虽然我很想把我对 Spring 的明白完全论述清楚,可是所谓“书不尽言,言不尽意”。,有什么差池或者不清楚的地方大家还是看看其源码吧。


本文关键词:「,技术,条记,博亚体育,」,成都,校区,Spring,框架,的

本文来源:博亚体育app官网-www.gxcjzk.com