第十三章 Spring框架的设计理念与设计模式分析
- 13.1 Spring的骨骼架构
Spring的设计理念
Spring就是面向Bean编程(BOP,Bean Oriented Programming)。Bean在Spring中的作用就像Object对OOP的意义一样,没有对象的概念就没有面向对象编程,Spring中没有Bean就没有Spring存在的意义。Spring可以让你把对象之间的依赖关系转而用配置文件来管理,也就是它的依赖注入机制。而这个注入关系在一个Ioc的容器中管理,Ioc容器就是被Bean包裹的对象。Spring正式通过把对象包装在Bean中达到对这些对象管理以及一系列额外操作的目的。
核心组件如何协同工作
把Bean比作一场演出的演员,Context就是这场演出的舞台背景,而Core应该就是演出的道具。Bean包装的是Object,而Object必然有数据,如何给这些数据提供生存环境就是Context要解决的问题,对Context来说它就是要发现每个Bean之间的关系,为它们建立这种关系并且维护好这种关系。所以Context就是一个Bean关系集合,这个关系集合又叫Ioc容器,,一旦建立起Ioc容器,Spring就可以为你工作。Core组件就是发现、建立、维护每个Bean之间的关系所需要的一系列工具。
- 13.2 核心组件详解
Bean组件
Bean组件在Spring的org.springframework.beans包下,这个包下所有类主要解决了三件事:Bean定义,Bean创建、Bean解析。
Spring Bean的创建是典型的工厂模式,它的顶级接口是BeanFactory。
BeanFactory有三个子类:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。定义不同层次的每个接口都有自己的使用场合,主要是为了区分在Spring内部对象的传递和转化过程中,对对象的数据访问所做的限制。例如,ListtableBeanFactory接口表示这些Bean是可列表的,而HierarchicalBeanFactory表示的是这些Bean是有继承关系的,也就是每个Bean有可能有父Bean,AutowireCapableBeanFactory接口定义Bean的自动装配规则。这四个接口共同定义了Bean集合、Bean之间的关系和Bean行为。
Bean的定义完整描述了在Spring的配置文件中你定义的<bean/>节点中所有的信息,包括各种子节点。当Spring成功解析你定义的一个<bean/>节点后,在Spring内部它转化为BeanDefinition对象,以后所有的操作都是对这个对象进行的。
Bean的解析主要就是对Spring配置文件的解析。
Context组件
Context在Spring的org.springframework.context包下,它实际上就是给Spring提供一个运行环境,以保存各个对象的状态。
从图中看出,ApplicationContext继承了BeanFactory,这也说明了Spring容器中运行的主体对象是Bean。另外ApplicationContext继承了ResourceLoader接口,使得ApplicationContext可以访问到任何外部资源。
ApplicationContext的子类主要包含两个方面:
ConfigurationApplicationContext表示Context是可修改的,也就是在构建Context中用户可以动态添加或修改已有的配置信息。
WebApplicationContext就是为Web准备的Context,可以直接访问到ServletContext。
再往下分就是构建Context文件类型,接着就是访问Context方式。
总体来ApplicationContext必须完成以下事:
标识一个应用环境
利用BeanFactory创建Bean对象
保存对象的关系表
能够捕获各种事件
Core 组件
Resource接口封装了各种可能的资源类型,也就是对使用者来说屏蔽了文件类型的不同。对资源的提供者来说,如何把资源包装起来交给其他人用这也是一个问题。Reource接口继承了InputStreamSource接口,这个接口有getInputStream方法,返回的是InputStream类。这样所有的资源都可以通过InputStream类来获取,所以也屏蔽了资源的提供者。另外还有一个问题是加载资源的问题——资源的加载者要统一。
Ioc容器如何工作
如何创建BeanFactory工厂
Ioc容器实际上是Context组件结合其他两个组件共同构建了一个Bean关系网,构建的入口在AbstractApplicationContext类的refresh方法中。
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { //为刷新准备新的context this.prepareRefresh(); //刷新BeanFactory容器 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //创建BeanFactory this.prepareBeanFactory(beanFactory); try { //注册实现了BeanPostprocessor接口的bean this.postProcessBeanFactory(beanFactory); //初始化和执行BeanFactoryPostProcessors bean this.invokeBeanFactoryPostProcessors(beanFactory); //初始化和执行BeanPostProcessors bean this.registerBeanPostProcessors(beanFactory); //初始化MessageSource this.initMessageSource(); //初始化event multicaster this.initApplicationEventMulticaster(); //刷新由子类实现的方法 this.onRefresh(); //检查注册事件 this.registerListeners(); //初始化non-lazy-init单例bean this.finishBeanFactoryInitialization(beanFactory); //Event事件 this.finishRefresh(); } catch (BeansException var9) { if(this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } //销毁beans this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } }
以上代码包含这样几个步骤:
1)构建BeanFactory,以便于产生所需要的演员
2)注册可能感兴趣的事件
3)创建Bean实例对象
4)触发被监听的事件
首先创建和配置BeanFactory,这里是refresh,也就是刷新配置。前面介绍了Context有可更新的子类,这里正是实现了这个功能,当BeanFactory已存在时就更新,不存在就新创建。下面是更新BeanFactory的方法的代码:
protected final void refreshBeanFactory() throws BeansException { if(hasBeanFactory()) { destroyBean(); closeBeanFactory(); } try{ DefualtListtableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized(this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error pasing bean definition source for" + getDisplayName(), ex); } }
BeanFactory的原始对象是DefaultListableBeanFactory。
创建好BeanFactory后,添加一些Spring本身需要的一些工具类,这个操作在AbstractApplicationContext的prepareBeanFactory方法中完成。
AbstractApplicationContext中接下来三行代码对Spring扩展性起了很重要的作用,前两行主要是对已构建的BeanFactory的配置做修改,后面一行就是你可以对以后再创建Bean实例对象时添加一些自定义的操作。
其中在invokeBeanFactoryPostProcessors方法中主要是获取实现BeanFactoryPostProcessor接口的子类,并执行它的postProcessBeanFactory方法。
void postProcessBenaFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException;
它的参数是beanFactory,说明可以对beanFactory做修改,这里注意,beanFactory是ConfigurableListableBeanFactory类型的,这也验证了前面介绍的不同BeanFactory所使用的场合不同,这里只能是可配置的BeanFactory,防止一些数据被用户随意修改。
registerBeanPostProcessors方法也可以获取用户定义的实现了BeanPostProcessor中声明了两个方法:postProcessBeforeInitialization和postProcessAfterInitialization,分别用于在Bean对象初始化时执行,可执行用户自定义的操作。
如何创建Bean实例并构建Bean的关系网
public void preInstantiateSingletons() throws BeanException{ if(this.logger.isInfoEnable()){ 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()) { final FactoryBean factory = (FactoryBean) getBean(Factory_BEAN_PREFIX+bean); boolean isEagerInit; if(System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>(){ public Boolean run() { return ((SmartFactory) factory).isEagerInit(); }, getAccessControlContext()); } else { isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactory) factory).isEgerInit(); } if(isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } } }
这里出现了一个非常重要的Bean——BeanFactory,可以说Spring一大半扩展功能都与这个Bean有关,这是个特殊的Bean。它是一个工厂Bean,可以生产Bean的Bean,这里的产生的Bean是指Bean的实例,如果一个类继承FactoryBean用户可以自己定义产生的实例对象的方法,只需要实现它的getObject方法。然而在Spring内部,这个Bean的实例对象是Factory,通过调用这个对象的getObject方法就能获取用户自定义产生的对象,从而为Spring提供了很好的扩展性
Ioc容器的扩展点
对Spring的Ioc容器来说,主要有BeanFactoryPostProcessor和BeanPostprocessor,它们分别在构建BeanFactory和构建Bean对象时调用。还有就是InitializingBean和DisposableBean,它们分别在Bean实例创建和销毁时被调用。用户可以实现这些接口中定义的方法,Spring会在适当的时候调用它们。还有一个是FactoryBean,它是一个特殊的Bean,可以被用户更多的控制。
把Ioc容器比作一个箱子,这个箱子里有若干个球的模子,可以用这些模子造很多种不同的球,还有一个造这些球模的机器,球模就是Bean,而球模造出来的球就是Bean的实例。BeanFactoryPostProcessor对应到当造球模被造出来时,此时有机会对其做出适当的修正,也就是它可以帮你修改球模。而InitializingBean和DisposableBean是在球模造出来的球做适当的修正。还有就是FactoryBean,这个球模不是预先就定型的,而是由你给它确定的形状。既然你可以确定这个球模型的形状,当然它造出来的球肯定就是你想要的球。
Ioc容器如何为我所用
Ioc实际上为你构建了一个魔方,Spring为你搭建了骨架结构,利用上面说的扩展点。
- 13.3 Spring中AOP特性详解
动态代理的实现原理
AOP是基于动态代理实现的。动态代理要从JDK本身说起。
在JDK的java.lang.reflect包下有个Proxy类,这正是构造代理类入口。
public static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHander h) throws IllegalArgmentException{ if(h == null) { throw new NullPointerException(); } Class c1 = getProxyClass(loader, interfaces); try{ `Constructor cons = c1.getConstructor(construcetorParams); return (Object) cons.newInstance(new Onject[] { h }); } catch(noSuchMethodException e) { throw new InternalError(e.toString()); } catch(IllegalAccessException e) { throw new InternalError(e.toString); } catch(InvocationTargetException e) { throw new InternalError(e.toString); } }
这个方法需要三个参数:ClassLoader,御用加载代理类的Loader类,通常这个Loader和被代理的类是同一个Loader类;Interfaces,是要被代理的那些接口;Invocationhandler,用于执行除了被代理接口中方法之外的用户自定义的操作,它也是用户需要代理的最终目的。用户调用目标方法都被代理到InvocationHandler类中定义的唯一方法invoke()中。
假如有这样一个接口:
public interface SimpleProxy { public void simpleMethod1(); public void simpleMethod2(); } //代理生成的接口 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方法。
<bean id="testBeanSingleton" class="org.springframework.app.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.springframework.app.framework.PrototypeTargetTest$TestBean</value> </property> <property name="target"><ref local="testBeanTarget"></ref></property> <property name="singleton"><value>true</value></property> <property name="interceptorName <list> <value>testInterceptor</value> <value>testInterceptor2</value> </list></property> </bean>
下面看看Spring如何完成代理
AOP是实现其自身的扩展点来完成这个特性,这个代理类可以看出它继承了FactoryBean的ProxyFactoryBean,FactoryBean之所以特别就子啊与它可以让自定义对象的创建方法。
13.4 设计模式解析之代理模式
代理模式原理
代理模式就是给某个对象创建一个代理对象,由这个代理对象控制对原对象的引用,而创建这个代理对象后可以在调用原对象时增加一些额外的操作。
Subject:抽象主题,它是代理对象的真实对象要实现的接口,当然这可以由多个接口组成
ProxySubject:代理类,除了实现抽象主题定义的接口外,还必须有所代理对象的引用
RealSubject:被代理的类,是目标对象
Spring中代理模式的实现
Spring AOP中JDK动态代理就是利用代理模式技术实现的。
$Proxy就是创建的代理对象,而Subject是抽象主题,代理对象是通过InvocationHandler来持有对目标对象的引用的。
public class $Proxy4 extends java.lang.reflect.Proxy implements org.springframework.aop.framework.PrototyeTargetTests$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 addVisor(int, org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException;
void addVisor(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;
boolean removeAdvice(org.aopalliance.aop.Advice);
java.lang.String toProxyConfigString();
boolean isFrozen();
void setExposeProxy(boolean);
boolean isExposeProxy();
}
- 13.5 设计模式解析之策略模式
策略模式原理
策略模式,就是做某事的策略,在编程上通常指完成某个操作可能有多种方法,这些方法各有千秋,可能有不同的是个的场合。把各个操作方法都当作一个实现的策略,使用者可根据需要选择合适的策略。
Context:使用不同策略的环境,它可以根据自身的条件选择不同的策略实现类来完成所需要的操作。它持有一个策略实例的引用。创建具体策略对象的方法也可以由它完成。
Strategy:抽象策略,定义每个策略都要实现的策略方法。
ConcreteStrategy:具体策略实现类,实现抽象策略中定义的策略方法
Spring中策略模式的实现
结构图与标准的策略模式结构稍有不同,这里策略是AopProxy接口,Cglib2AopProxy和jdkDynamicAopProxy分别代表两种策略的实现方式,ProxyFactoryBean代表Context角色,它根据条件选择JDK代理方式还是CGLIB方式。而另外三个类主要负责创建具体策略对象,ProxyFactoryBean是通过依赖的方法关联具体策略对象的。它通过调用策略对象的getProxy(ClassLoader classLoader)方法来完成操作。