第十三章 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)方法来完成操作。

posted @ 2016-04-01 16:12  水底的土豆  阅读(600)  评论(0)    收藏  举报