介: Spring 作ؓ现在最优秀的框架之一Q已被广泛的使用Qƈ且有很多对其分析的文章。本文将从另外一个视角试囑։析出 Spring 框架的作者设?Spring 框架的骨骼架构的设计理念Q有那几个核心组ӞZ么需要这些组Ӟ它们又是如何l合在一h?Spring 的骨骼架构? Spring ? AOP Ҏ又是如何利用这些基的骨骼架构来工作的? Spring 中又使用了那些设计模式来完成它的q种设计的?它的q种设计理念对对我们以后的Y件设计有何启C?本文详l解{这些问题?/p>
Spring d有十几个lgQ但是真正核心的lg只有几个Q下面是 Spring 框架的M架构图:
从上图中可以看出 Spring 框架中的核心lg只有三个QCore、Context ?Beans。它们构v了整?Spring 的骨骼架构。没有它们就不可能有 AOP、Web {上层的Ҏ功能。下面也主要从q三个组件入手分?Spring?/p>
前面介绍?Spring 的三个核心组Ӟ如果再在它们三个中选出核心的话Q那非 Beans lg莫属了,Zq样_其实 Spring 是面向 Bean 的编E(BOP,Bean Oriented ProgrammingQ,Bean ?Spring 中才是真正的主角?/p>
Bean ?Spring 中作用就?Object ?OOP 的意义一P没有对象的概念就像没有面向对象编E,Spring 中没? Bean 也就没有 Spring 存在的意义。就像一ơ演台都准备好了但是却没有演员一栗ؓ什么要 Bean q种角色 Bean 或者ؓ何在 Spring 如此重要Q这?Spring 框架的设计目标决定,Spring Z如此行Q我们用 Spring 的原因是什么,x你会发现原来 Spring 解决了一个非常关键的问题他可以让你把对象之间的依赖关p{而用配置文g来管理,也就是他的依赖注入机制。而这个注入关pd一个叫 Ioc 容器中管理,?Ioc 容器中有又是什么就是被 Bean 包裹的对象。Spring 正是通过把对象包装在 Bean 中而达到对q些对象理以及一些列额外操作的目的?/p>
它这U设计策略完全类g Java 实现 OOP 的设计理念,当然?Java 本n的设计要?Spring 复杂太多太多Q但是都是构Z个数据结构,然后Ҏq个数据l构设计他的生存环境Qƈ让它在这个环境中按照一定的规律在不停的q动Q在它们的不停运动中? 计一pd与环境或者与其他个体完成信息交换。这h来回q头x我们用到的其他框枉是大慨类似的设计理念?/p>
前面?Bean ?Spring 中关键因素,?Context ?Core 又有何作用呢Q前面吧 Bean 比作一场演Z的演员的话,?Context 是q场演出的舞台背景,?Core 应该是演出的道具了。只有他们在一h能具备能演出一场好戏的最基本的条件。当然有最基本的条件还不能使这场演颖而出Q还要他表演的节目够的_? 彩,q些节目是 Spring 能提供的特色功能了?/p>
我们知道 Bean 包装的是 ObjectQ?Object 必然有数据,如何l这些数据提供生存环境就?Context 要解决的问题Q对 Context 来说他就是要发现每个 Bean 之间的关p,为它们徏立这U关pdƈ且要l护好这U关pR所?Context 是一?Bean 关系的集合,q个关系集合又叫 Ioc 容器Q一旦徏立vq个 Ioc 容器?Spring 可以ؓ你工作了。那 Core lg又有什么用武之地呢Q其?Core 是发现、徏立和l护每个 Bean 之间的关pL需要的一些列的工P从这个角度看来,Core q个lg? Util 更能让你理解?/p>
它们之间可以用下图来表示Q?/p>
?2. 三个lg关系
q里详l介l每个组件内部类的层ơ关p,以及它们在运行时的时序顺序。我们在使用 Spring 是应该注意的地方?/p>
Bean lg
前面已经说明?Bean lg?Spring 的重要性,下面看看 Bean q个lg式怎么设计的。Bean lg?Spring ? org.springframework.beans 包下。这个包下的所有类主要解决了三件事QBean 的定义、Bean 的创Z及对 Bean 的解析。对 Spring 的用者来说唯一需要关心的是 Bean 的创建,其他两个?Spring 在内部帮你完成了Q对你来说是透明的?/p>
Spring Bean 的创建时典型的工厂模式,他的接口?BeanFactoryQ下图是q个工厂的承层ơ关p:
BeanFactory 有三个子c:ListableBeanFactory、HierarchicalBeanFactory ? AutowireCapableBeanFactory。但是从上图中我们可以发现最l的默认实现cL DefaultListableBeanFactoryQ他实现了所有的接口。那Z要定义这么多层次的接口呢Q查阅这些接口的源码和说明发玎ͼ每个接口 都有他用的场合Q它主要是ؓ了区分在 Spring 内部在操作过E中对象的传递和转化q程中,对对象的数据讉K所做的限制。例? ListableBeanFactory 接口表示q些 Bean 是可列表的,?HierarchicalBeanFactory 表示的是q些 Bean 是有l承关系的,也就是每?Bean 有可能有?Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义?Bean 的集合、Bean 之间的关pR以?Bean 行ؓ?/p>
Bean 的定义主要有 BeanDefinition 描述Q如下图说明了这些类的层ơ关p:
Bean 的定义就是完整的描述了在 Spring 的配|文件中你定义的 <bean/> 节点中所有的信息Q包括各U子节点。当 Spring 成功解析你定义的一?<bean/> 节点后,?Spring 的内部他p转化?BeanDefinition 对象。以后所有的操作都是对这个对象完成的?/p>
Bean 的解析过E非常复杂,功能被分的很l,因ؓq里需要被扩展的地方很多,必须保证有够的灉|性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文g的解析。这个解析过E主要通过下图中的cd成:
当然q有具体?tag 的解析这里ƈ没有列出?/p>
Context lg
Context ?Spring ?org.springframework.context 包下Q前面已l讲解了 Context lg? Spring 中的作用Q他实际上就是给 Spring 提供一个运行时的环境,用以保存各个对象的状态。下面看一下这个环境是如何构徏的?/p>
ApplicationContext ?Context 的顶U父c,他除了能标识一个应用环境的基本信息外,他还l承了五个接口,q五个接口主要是扩展?Context 的功能。下面是 Context 的类l构图:
Q查??7 的清晰版?/font>。)
从上图中可以看出 ApplicationContext l承?BeanFactoryQ这也说明了 Spring 容器中运行的M对象? BeanQ另?ApplicationContext l承?ResourceLoader 接口Q?ApplicationContext 可以讉KCQ何外部资源,q将?Core 中详l说明?/p>
ApplicationContext 的子cM要包含两个方面:
再往下分是按照构徏 Context 的文件类型,接着是讉K Context 的方式。这样一U一U构成了完整?Context {层次?/p>
M来说 ApplicationContext 必须要完成以下几件事Q?/p>
Context 作ؓ Spring ?Ioc 容器Q基本上整合?Spring 的大部分功能Q或者说是大部分功能的基?/p>
Core lg
Core lg作ؓ Spring 的核心组Ӟ他其中包含了很多的关键类Q其中一个重要组成部分就是定义了资源的访问方式。这U把所有资源都抽象成一个接口的方式很值得在以后的设计中拿来学习。下面就重要看一下这个部分在 Spring 的作用?/p>
下图?Resource 相关的类l构图:
Q查??8 的清晰版?/font>。)
从上囑֏以看?Resource 接口装了各U可能的资源cdQ也是对用者来说屏蔽了文gcd的不同。对资源的提供者来_如何把资源包装v来交l其他h用这也是一个问题,我们看到 Resource 接口l承?InputStreamSource 接口Q这个接口中有个 getInputStream ҎQ返回的? InputStream cR这h有的资源都被可以通过 InputStream q个cL获取Q所以也屏蔽了资源的提供者。另外还有一个问题就是加载资源的问题Q也是资源的加载者要l一Q从上图中可以看个Q务是? ResourceLoader 接口完成Q他屏蔽了所有的资源加蝲者的差异Q只需要实现这个接口就可以加蝲所有的资源Q他的默认实现是 DefaultResourceLoader?/p>
下面看一?Context ?Resource 是如何徏立关pȝQ首先看一下他们的cdpdQ?/p>
?9. Context ?Resource 的类关系?/font>
从上囑֏以看出,Context 是把资源的加载、解析和描述工作委托l了 ResourcePatternResolver cL完成Q他相当于一个接头hQ他把资源的加蝲、解析和资源的定义整合在一起便于其他组件用。Core lg中还有很多类似的方式?/p>
Ioc 容器如何工作
前面介绍?Core lg、Bean lg?Context lg的结构与怺关系Q下面这里从使用者角度看一下他们是如何q行的,以及我们如何?Spring 完成各种功能QSpring 到底能有那些功能Q这些功能是如何得来的,下面介绍?/p>
如何创徏 BeanFactory 工厂
正如?2 描述的那PIoc 容器实际上就?Context lgl合其他两个lg共同构徏了一?Bean
关系|,如何构徏q个关系|?构徏的入口就?AbstractApplicationContext cȝ refresh
Ҏ中。这个方法的代码如下Q?/p>
清单 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; } } } |
q个Ҏ是构徏整个 Ioc 容器q程的完整的代码Q了解了里面的每一行代码基本上׃解大部分 Spring 的原理和功能了?/p>
q段代码主要包含q样几个步骤Q?/p>
下面q合代码分析这几个q程?/p>
W二三句是在创建和配置 BeanFactory。这里是 refresh 也就是刷新配|,前面介绍?Context 有可更新的子c,q里正是实现q个功能Q当 BeanFactory 已存在是更斎ͼ如果没有新创徏。下面是更新 BeanFactory 的方法代码:
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); } } |
q个Ҏ实现?AbstractApplicationContext 的抽象方? refreshBeanFactoryQ这D代码清楚的说明?BeanFactory 的创E。注?BeanFactory 对象的类型的变化Q前面介l了他有很多子类Q在什么情况下使用不同的子c这非常关键。BeanFactory 的原始对象是 DefaultListableBeanFactoryQ这个非常关键,因ؓ他设计到后面对这个对象的多种操作Q下面看一下这个类的承层ơ类图:
Q查??10 的清晰版?/font>。)
从这个图中发现除?BeanFactory 相关的类外,q发C?Bean ?register 相关。这? refreshBeanFactory Ҏ中有一?loadBeanDefinitions(beanFactory) 找到答案,q个Ҏ开始加载、解?Bean 的定义,也就是把用户定义的数据结构{化ؓ Ioc 容器中的特定数据l构?/p>
q个q程可以用下面时序图解释Q?/p>
?11. 创徏 BeanFactory 时序?/font>
Q查??11 的清晰版?/font>。)
Bean 的解析和登记程时序囑֦下:
Q查??12 的清晰版?/font>。)
创徏?BeanFactory 后,接下L加一?Spring 本n需要的一些工LQ这个操作在 AbstractApplicationContext ?prepareBeanFactory Ҏ完成?/p>
AbstractApplicationContext 中接下来的三行代码对 Spring 的功能扩展性v了至关重要的作用。前两行主要是让你现在可以对已经构徏?BeanFactory 的配|做修改Q后面一行就是让你可以对以后再创? Bean 的实例对象时d一些自定义的操作。所以他们都是扩展了 Spring 的功能,所以我们要学习使用 Spring 必须对这一部分搞清楚?/p>
其中?invokeBeanFactoryPostProcessors Ҏ中主要是获取实现 BeanFactoryPostProcessor 接口的子cRƈ执行它的 postProcessBeanFactory ҎQ这个方法的声明如下Q?/p>
清单 3. BeanFactoryPostProcessor.postProcessBeanFactory
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; |
它的参数?beanFactoryQ说明可以对 beanFactory 做修改,q里注意q个 beanFactory ? ConfigurableListableBeanFactory cd的,q也印证了前面介l的不同 BeanFactory 所使用的场合不同,q里只能是可配置?BeanFactoryQ防止一些数据被用户随意修改?/p>
registerBeanPostProcessors Ҏ也是可以获取用户定义的实C BeanPostProcessor 接口的子c,q执行把它们注册?BeanFactory 对象中的 beanPostProcessors 变量中。BeanPostProcessor 中声明了两个ҎQpostProcessBeforeInitialization、postProcessAfterInitialization 分别用于?Bean 对象初始化时执行。可以执行用戯定义的操作?/p>
后面的几行代码是初始化监听事件和对系l的其他监听者的注册Q监听者必L ApplicationListener 的子cR?/p>
如何创徏 Bean 实例q构?Bean 的关pȝ
下面是 Bean 的实例化代码Q是?finishBeanFactoryInitialization Ҏ开始的?/p>
清单 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 Ҏ的代码如下:
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<Boolean>() { public Boolean run() { return ((SmartFactoryBean) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit(); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } } } |
q里出现了一个非帔R要的 Bean —?FactoryBeanQ可以说 Spring 一大半的扩展的功能都与q个 Bean 有关Q这是个Ҏ?Bean 他是个工?BeanQ可以?Bean ?BeanQ这里的产生 Bean 是指 Bean 的实例,如果一个类l承 FactoryBean 用户可以自己定义产生实例对象的方法只要实C?getObject Ҏ。然而在 Spring 内部q个 Bean 的实例对象是 FactoryBeanQ通过调用q个对象?getObject Ҏp获取用户自定义生的对象Q从而ؓ Spring 提供了很好的扩展性。Spring 获取 FactoryBean 本n的对象是在前面加?& 来完成的?/p>
如何创徏 Bean 的实例对象以及如何构?Bean 实例对象之间的关联关pd Spring 中的一个核心关键,下面是这个过E的程图?/p>
?13.Bean 实例创徏程?/font>
Q查??13 的清晰版?/font>。)
如果是普通的 Bean q接创Z的实例,是通过调用 getBean Ҏ。下面是创徏 Bean 实例的时序图Q?/p>
?14.Bean 实例创徏时序?/font>
Q查??14 的清晰版?/font>。)
q有一个非帔R要的部分是建立 Bean 对象实例之间的关p,q也?Spring 框架的核心竞争力Q何时、如何徏立他们之间的关系L下面的时序图Q?/p>
?15.Bean 对象关系建立
Q查??15 的清晰版?/font>。)
Ioc 容器的扩展点
现在q有一个问题就是如何让q些 Bean 对象有一定的扩展性,是可以加入用户的一些操作。那么有哪些扩展点呢Q?Spring 又是如何调用到这些扩展点的?
?Spring ?Ioc 容器来说Q主要有q么几个。BeanFactoryPostProcessorQ? BeanPostProcessor。他们分别是在构?BeanFactory 和构?Bean 对象时调用。还有就? InitializingBean ?DisposableBean 他们分别是在 Bean 实例创徏和销毁时被调用。用户可以实现这些接口中定义的方法,Spring ׃在适当的时候调用他们。还有一个是 FactoryBean 他是个特D的 BeanQ这?Bean 可以被用h多的控制?/p>
q些扩展炚w常也是我们使用 Spring 来完成我们特定Q务的地方Q如何精?Spring q你有没有掌握?Spring 有哪些扩展点Qƈ且如何用他们,要知道如何用他们就必须了解他们内在的机理。可以用下面一个比L解释?/p>
我们?Ioc 容器比作一个箱子,q个子里有若干个球的模子,可以用这些模子来造很多种不同的球Q还有一个造这些球模的机器Q这个机器可以生球模。那么他们的对应? pd?BeanFactory 是那个造球模的机器Q球模就?BeanQ而球模造出来的球就?Bean 的实例。那前面所说的几个扩展点又在什么地方呢Q?BeanFactoryPostProcessor 对应到当造球模被造出来时Q你有Z可以对其做出讑ֽ的修正,也就是他可以帮你修改球模。?InitializingBean ? DisposableBean 是在球模造球的开始和l束阶段Q你可以完成一些预备和扫尾工作。BeanPostProcessor 可以让你对球模造出来的球做出适当的修正。最后还有一? FactoryBeanQ它可是一个神奇的球模。这个球模不是预先就定型了,而是׃来给他确定它的ŞӞ既然你可以确定这个球模型的ŞӞ当然他造出? 的球肯定是你想要的球了Q这样在q个子里尼可以发现所有你惌的球
Ioc 容器如何为我所?/strong>
前面的介l了 Spring 容器的构E,?Spring 能ؓ我们做什么,Spring ?Ioc 容器又能做什么呢Q我们? Spring 必须要首先构?Ioc 容器Q没有它 Spring 无法工作QApplicatonContext.xml 是 Ioc 容器的默认配|文ӞSpring 的所有特性功能都是基于这?Ioc 容器工作的,比如后面要介l的 AOP?/p>
Ioc 它实际上是Z构徏了一个魔方,Spring Z搭好了骨骼架构,q个方到底能变Z么好的东西出来,q必要有你的参与。那我们怎么参与Q这是前面说的要了?Spring 中那有些扩展点,我们通过实现那些扩展Ҏ改变 Spring 的通用行ؓ。至于如何实现扩展点来得到我们想要的个性结果,Spring 中有很多例子Q其?AOP 的实现就?Spring 本n实现了其扩展Ҏ辑ֈ了它惌的特性功能,可以拿来参考?/p>
要了?Spring ?AOP 必d了解的动态代理的原理Q因?AOP 是Z动态代理实现的。动态代理还要从 JDK 本n说v?/p>
?Jdk ?java.lang.reflect 包下有个 Proxy c,它正是构造代理类的入口。这个类的结构入下:
从上囑֏现最后面四个是公有方法。而最后一个方?newProxyInstance 是创徏代理对象的方法。这个方法的源码如下Q?/p>
清单 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()); } } |
q个Ҏ需要三个参敎ͼClassLoaderQ用于加载代理类?Loader c,通常q个 Loader 和被代理的类是同一? Loader cRInterfacesQ是要被代理的那些那些接口。InvocationHandlerQ就是用于执行除了被代理接口中方法之外的用户自定义的操作Q? 他也是用户需要代理的最l目的。用戯用目标方法都被代理到 InvocationHandler cM定义的唯一Ҏ invoke 中。这在后面再详解?/p>
下面q是看看 Proxy 如何产生代理cȝq程Q他构造出来的代理cd底是什么样子?下面揭晓啦?/p>
?17. 创徏代理对象时序?/font>
其实从上图中可以发现正在构造代理类的是?ProxyGenerator ?generateProxyClass 的方法中。ProxyGenerator cd sun.misc 包下Q感兴趣的话可以看看他的源码?/p>
假如有这样一个接口,如下Q?/p>
清单 7. SimpleProxy c?/font>
public interface SimpleProxy { public void simpleMethod1(); public void simpleMethod2(); } |
代理来生成的cȝ构如下:
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(); } |
q个cM的方法里面将会是调用 InvocationHandler ?invoke ҎQ而每个方法也对应一个属性变量,q个属性变?m 也将传给 invoke Ҏ中的 Method 参数。整个代理就是这样实现的?/p>
从前面代理的原理我们知道Q代理的目的是调用目标方法时我们可以转而执?InvocationHandler cȝ invoke ҎQ所以如何在 InvocationHandler 上做文章是 Spring 实现 Aop 的关键所在?/p>
Spring ?Aop 实现是遵?Aop 联盟的约定。同?Spring 又扩展了它,增加了如 Pointcut、Advisor {一些接口得更加灵zR?/p>
下面?Jdk 动态代理的cdQ?/p>
?18. Jdk 动态代理的cd
上图清楚的显CZ Spring 引用?Aop Alliance 定义的接口。姑且不讨论 Spring 如何扩展 Aop
AllianceQ先看看 Spring 如何实现代理cȝQ要实现代理cd Spring 的配|文件中通常是这样定一?Bean 的,如下Q?/p>
清单 9. 配置代理c?Bean
<bean id="testBeanSingleton" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value> org.springframework.aop.framework.PrototypeTargetTests$TestBean </value> </property> <property name="target"><ref local="testBeanTarget"></ref> </property> <property name="singleton"><value>true</value></property> <property name="interceptorNames"> <list> <value>testInterceptor</value> <value>testInterceptor2</value> </list> </property> </bean> |
配置上看到要讄被代理的接口Q和接口的实现类也就是目标类Q以及拦截器也就在执行目标方法之前被调用Q这?Spring 中定义的各种各样的拦截器Q可以选择使用?/p>
下面看看 Spring 如何完成了代理以及是如何调用拦截器的?/p>
前面提到 Spring Aop 也是实现其自w的扩展Ҏ完成q个Ҏ的Q从q个代理cd以看出它正是l承?FactoryBean ? ProxyFactoryBeanQFactoryBean 之所以特别就在它可以让你自定义对象的创徏Ҏ。当然代理对象要通过 Proxy cL动态生成?/p>
下面?Spring 创徏的代理对象的时序图:
Spring 创徏了代理对象后Q当你调用目标对象上的方法时Q将都会被代理到 InvocationHandler cȝ invoke Ҏ中执行,q在前面已经解释。在q里 JdkDynamicAopProxy cdC InvocationHandler 接口?/p>
下面再看?Spring 是如何调用拦截器的,下面是这个过E的时序图:
以上所说的都是 Jdk 动态代理,Spring q支持一U?CGLIB cM理,感兴自q吧?/p>
Spring 中用的设计模式也很多,比如工厂模式、单例模式、模版模式等Q在?Webx 框架的系l架构与设计模式》、?Tomcat 的系l架构与模式设计分析》已l有介绍Q这里就不赘qC。这里主要介l代理模式和{略模式?/p>
代理模式原理
代理模式是l某一个对象创Z个代理对象,而由q个代理对象控制对原对象的引用,而创个代理对象就是可以在调用原对象是可以增加一些额外的操作。下面是代理模式的结构:
Spring 中如何实C理模?/strong>
Spring Aop ?Jdk 动态代理就是利用代理模式技术实现的。在 Spring 中除了实现被代理对象的接口外Q还会有 org.springframework.aop.SpringProxy ? org.springframework.aop.framework.Advised 两个接口。Spring 中用代理模式的l构囑֦下:
$Proxy 是创徏的代理对象,?Subject 是抽象主题,代理对象是通过 InvocationHandler 来持有对目标对象的引用的?/p>
Spring 中一个真实的代理对象l构如下Q?/p>
清单 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(); } |
{略模式原理
{略模式思义是做某事的{略Q这在编E上通常是指完成某个操作可能有多U方法,q些Ҏ各有千秋Q可能有不同的适应的场合,然而这些操作方法都有可能用到。各一个操作方法都当作一个实现策略,使用者可能根据需要选择合适的{略?/p>
下面是策略模式的l构Q?/p>
?23. {略模式的结?/font>
Spring 中策略模式的实现
Spring 中策略模式用有多个地方Q如 Bean 定义对象的创Z及代理对象的创徏{。这里主要看一下代理对象创建的{略模式的实现?/p>
前面已经了解 Spring 的代理方式有两个 Jdk 动态代理和 CGLIB 代理。这两个代理方式的用正是用了{略模式。它的结构图如下所C:
在上面结构图中与标准的策略模式结构稍微有点不同,q里抽象{略?AopProxy 接口QCglib2AopProxy ? JdkDynamicAopProxy 分别代表两种{略的实现方式,ProxyFactoryBean 是代表 Context 角色Q它Ҏ条g选择使用 Jdk 代理方式q是 CGLIB 方式Q而另外三个类主要是来负责创徏具体{略对象QProxyFactoryBean 是通过依赖的方法来兌具体{略对象的,它是通过调用{略对象?getProxy(ClassLoader classLoader) Ҏ来完成操作?/p>
本文通过?Spring 的几个核心组件入手,试图扑և构徏 Spring 框架的骨骼架构,q而分?Spring 在设计的一些设计理念,是否从中扑և一些好的设计思想Q对我们以后E序设计能提供一些思\。接着再详l分析了 Spring 中是如何实现q些理念的,以及在设计模式上是如何用的?/p>
通过分析 Spring l我一个很大的启示是其这套设计理念其实对我们有很强的借鉴意义Q它通过抽象复杂多变的对象,q一步做规范Q然后根据它定义的这套规范设计出一个容器,容器中构建它们的复杂关系Q其实现在有很多情况都可以用q种cM的处理方法?/p>
虽然我很x我对 Spring 的想法完全阐q清楚,但是所?#8220;书不言Q言不尽意?#8221;Q有什么不Ҏ者不清楚的地方大家还是看看其源码吧?/p>
原文地址 http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/index.html