天天看点

Spring技术内幕——读书笔记

Spring技术内幕

第1章 Spring的设计理念和整体架构(略)

第2章 Spring Framework的核心:IoC容器的实现

两个主要容器:

  1. 实现

    BeanFactory

    接口的简单容器系列:实现容器的最基本功能
  2. ApplicationContext

    :增加了许多面向框架的特性,同时对应用环境作了许多适配

IoC容器的接口设计图:

Spring技术内幕——读书笔记

BeanFactory

接口方法:

-

containsBean

-

isSingleton

-

isPrototype

-

isTypeMatch

-

getType

-

getAliases

设计原理:(以

XmlBeanFactory

为例)

编程式使用IoC容器:

ClassPathResource res = new ClassPathResource("bean.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(res);
           

步骤:

1. 创建IoC配置文件的抽象资源,这个抽象资源包含了

BeanDefinition

的定义信息

2. 创建一个

BeanFactory

,这里使用

DefaultListableBeanFactory

3. 创建一个载入

BeanDefinition

的读取器,通过一个回调配置给

BeanFactory

4. 从定义好的资源位置读入配置信息,具体的解析过程由

XmlBeanDefinitionReader

来完成。

IoC容器的初始化过程

Resource定位过程:

Spring技术内幕——读书笔记

BeanDefinition的载入和解析:

对IoC容器来说,这个载入过程,相当于把定义的

BeanDefinition

在IoC容器中转化为一个Spring内部表示的数据结构的过程,这些

BeanDefinition

数据在IoC容器中通过一个

HashMap

来保持和维护。

Spring技术内幕——读书笔记

BeanDefinition在IoC容器中的注册:

DefaultListableBeanFactory

中实现了

BeanDefinitionRegistry

的接口,这个接口的实现完成

BeanDefinition

向容器的注册,就是把解析得到的

BeanDefinition

设置到

hashMap

中去。

Spring技术内幕——读书笔记

IoC容器的依赖注入

什么时候注入:在用户第一次向IoC容器索要bean的时候(

lazy-init

预实例化除外)

Spring技术内幕——读书笔记

两种实例化Java对象的方法:

- 通过

BeanUtils

,使用Java反射功能

- 通过

CGLIB

Enhancer

类的

create

方法

容器初始化和关闭过程

Spring技术内幕——读书笔记

Bean的生命周期:

1. Bean实例的创建

2. 为Bean实例设置属性

3. 调用Bean的初始化方法

4. 应用可以通过IoC容器使用Bean

5. 当容器关闭时,调用Bean的销毁方法

lazy-init属性和预实例化:在

refresh

初始化容器的时候去

getBean

去触发依赖注入

FactoryBean的实现:类似于抽象工厂模式,封装Proxy、RMI、JNDI等

BeanPostProcessor的实现:

两个方法:

postProcessBeforeInitialization

/

postProcessAfterInitialization

IoC容器对Bean的初始化

- 为类型是

BeanNameAware

的Bean设置Bean的名字

- 为类型是

BeanClassLoaderAware

的Bean设置类装载器

- 为类型是

BeanFactoryAware

的Bean设置自身所在的IoC容器以供回调使用

- 对

postProcessBeforeInitialization

/

postProcessAfterInitialization

的回调

- 初始化属性

init-method

的处理

autowiring(自动依赖装配)的实现

//开始进行依赖注入过程,先处理autowiring的注入
    if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        //这里是对autowire注入的处理,根据Bean的名字或者type进行autowire的过程
        if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
           

第3章 Spring AOP的实现

Spring AOP概述

Advice

通知:

-

BeforeAdvice

:接口

MethodBeforeAdvice

,方法

before()

-

AfterAdvice

:接口

AfterReturningAdvice

,方法

afterReturning()

-

ThrowsAdvice

:在抛出异常时回调,这个回调是AOP通过反射机制完成的。

Pointcut

切点:

概念:决定

Advice

通知应该作用于哪个连接点。返回一个

MethodMatcher

,由它来判断是否需要对当前方法调用进行增强,或者是否需要对当前调用方法应用配置好的

Advice

通知。

  • 通过正则表达式进行匹配
  • 通过方法名进行匹配
  • 等等

Spring AOP的设计和实现

JVM动态代理

Spring技术内幕——读书笔记

Advisor通知器:

概念:将

Advice

pointcut

结合起来,可以定义应该使用哪个通知在哪个关注点使用。

建立AopProxy代理对象

ProxyFactoryBean:封装了主要代理对象的生成过程,生成方式有两种

- JDK的Proxy

- CGLIB

Spring技术内幕——读书笔记

JDK生成

AopProxy

代理对象

public Obejct getObject(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class[] proxiedInterfaces AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //这是调用JDK生成Proxy的地方
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
           

拦截器调用的实现

JdkDynamicAopProxy

invoke

拦截:

当Proxy对象的代理方法被调用的时候,

JdkDynamicAopProxy

invoke

方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,构造

ReflectiveMethodInvocation

对象来完成对目标对象方法调用的拦截或者说功能增强。

Cglib2AopProxy

intercept

拦截:

JdkDynamicAopProxy

的回调实现非常类似,唯一不同的是构造

CglibMethodInvocation

对象来完成拦截器链的调用。

对目标方法的调用:

- jdk:使用反射机制得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。

- cglib:通过

MethodProxy

对象来直接invoke完成的

AOP拦截器链的调用:

1. 先进行判断,如果已经运行到拦截器链的末尾,直接调用目标对象的实现方法

2. 否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行

matches

判断,是否适用于横切增强的场合,如果是,从拦截器中得到通知器,并启动通知器的

invoke

方法进行切面增强

3. 结束之后,迭代调用

proceed

方法,直到拦截器链中的拦截器都完成以上的拦截过程为止

配置通知器:

MethodBeforeAdviceAdapter

的实现

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}
           

MethodBeforeAdviceInterceptor

的实现

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

    private MethodBeforeAdvice advice;


    //为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

//这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        return mi.proceed();
    }
}
           

AfterReturningAdviceInterceptor

的实现

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

    private final AfterReturningAdvice advice;


    /**
     * Create a new AfterReturningAdviceInterceptor for the given advice.
     * @param advice the AfterReturningAdvice to wrap
     */
    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

}
           

Spring AOP的高级特性

HotSwappableTaregetSource

:使用户可以以线程安全的方式切换目标对象,提供所谓的热交换功能。

public synchronized Object swap(Object newTarget) throws IllegalArgumentException {
        Assert.notNull(newTarget, "Target object must not be null");
        Object old = this.target;
        this.target = newTarget;
        return old;
    }

public synchronized Object getTarget() {
        return this.target;
    }
           

第4章 Spring MVC与Web环境

Web环境中的Spring MVC:

SpringMVC是建立在IoC容器基础上的,该容器由

web.xml

里配置的

ContextLoaderListener

负责启动的。

上下文在Web容器的启动:

Spring技术内幕——读书笔记

Spring MVC的设计和实现

DispatcherServlet

的处理过程:

Spring技术内幕——读书笔记

doDispatch

协同模型和控制器的过程:

Spring技术内幕——读书笔记

Handler

的如何获得:

1. 首先会在

HttpRequest

中取得

handler

2. 如果没有,则遍历当前

DispatcherServlet

持有的所有

handlerMapping

,返回需要的

handler

Spring MVC视图的呈现

DispathcherServlet

render

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale = this.localeResolver.resolveLocale(request);
    response.setLocale(locale);

    View view;
    if (mv.isReference()) {
        // We need to resolve the view name.
        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                    "' in servlet with name '" + getServletName() + "'");
        }
    }
    else {
        // No need to lookup: the ModelAndView object contains the actual View object.
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                    "View object in servlet with name '" + getServletName() + "'");
        }
    }

    // Delegate to the View object for rendering.
    if (logger.isDebugEnabled()) {
        logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
    }
    try {
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
                    getServletName() + "'", ex);
        }
        throw ex;
    }
}
           

第5章 数据库操作组件的实现

Spring JDBC

JdbcTemplate

execute

实现:

Spring技术内幕——读书笔记

JdbcTemplate

query

实现:

Spring技术内幕——读书笔记

Spring JDBC中RDBMS操作对象的实现

SqlQuery

的实现:

Spring技术内幕——读书笔记

SqlUpdate

的实现:

Spring技术内幕——读书笔记

SqlFunction:

Spring技术内幕——读书笔记

Spring驱动Hibernate的设计和实现

基本配置Bean:

LocalSessionFactoryBean

,生成

SessionFactory

,并对Hibernate中的

Session

进行管理

Spring技术内幕——读书笔记

Session的管理:

Spring对Hibernate

Session

的管理功能都是由

SessionFactoryUtils

这个类来提供的。

1. 如果当前线程已绑定事务,

Session

使用的

Connection

是当前线程绑定的那个

2. 新建

Session

和单独使用

SessionFactory

打开新

Session

一样,都是使用

SessionFactory

openSession

来创建新的

Session

Spring驱动iBatis的设计与实现

iBatis操作数据库的主要类:

SqlMapClient

,类似于Hibernate的

Session

,是由

SqlMapClientFactoryBean

在依赖注入完成以后被IoC容器回调

afterPropertiesSet

中完成创建的。

Spring技术内幕——读书笔记

第6章 Spring事务处理的实现

Spring声明式事务处理

Spring技术内幕——读书笔记

Spring事务处理的设计与实现

事务的创建:

Spring技术内幕——读书笔记

事务创建的结果是生成一个

TransactionStatus

对象,通过这个对象来保存事务处理需要的基本信息,这个是

TransactionInfo

的一个属性,然后会把

TransactionInfo

保存在

ThreadLocal

对象里,这样当前线程可以通过

ThreadLocal

对象取得

TransactionInfo

以及与这个事务对应的

TransactionStatus

对象,从而把处理信息和调用事务方法的当前线程绑定起来。

Spring事务处理

DataSourceTransactionManager

的实现:

Spring技术内幕——读书笔记

HibernateTransactionManager

的实现:

Spring技术内幕——读书笔记

第7章 Spring远端调用的实现

Spring HTTP调用器的实现

HTTP调用客户端的实现:

Spring技术内幕——读书笔记

HTTP调用器客户端完成远端调用的基本过程:

首先由客户端应用调用代理方法,在调用发生以后,代理类会先运行拦截器,对代理的方法调用进行拦截。在拦截器的拦截行为中,先对本地发生的方法调用进行封装 ,具体来说,就是封装成

MethodInvocation

对象。然后,把这个

MethodInvocation

对象,通过序列化和HTTP请求发送到服务器端,在服务器端的处理完成以后,会通过HTTP响应返回处理结果,这个处理结果被风中在

RemoteInvocationResult

对象中。

HTTP调用服务端的实现:

Spring技术内幕——读书笔记

Spring RMI的实现

Spring RMI客户端的实现:

Spring技术内幕——读书笔记

第8章 安全框架ACEGI的设计与实现

概述

Spring技术内幕——读书笔记

ACGEI验证器的实现

过程:

1. 从

AuthenticationProcessingFilter

拦截HTTP请求开始,接着会从HTTP请求中得到用户输入的用户名和密码,并将这些输入的用户信息放到

Authentication

对象中。

2. 将这个

Authentication

对象传递给

AuthenticationManager

使用,验证器通过持有的

Authentication

对象把它和服务端取得的用户信息进行对比,从而完成用户验证。

3. 验证完成以后,ACEGI会把通过验证的、有效的用户信息封装在一个

Authentication

对象中,供以后的授权器使用

在验证的实现过程中,需要根据ACEGI的要求,配置好各种Provider、UserDetailService以及密码Encoder对象,通过这些对象的协作和功能实现,完成服务器用户数据的获取与用户输入信息的对比和最终的用户验证工作。

ACEGI授权器的实现

过程:

1. 从

FilterSecurityInterceptor

拦截HTTP入手,接着在读取在IoC容器中配置的对URL资源的安全需求以后,会把这些配置信息交由

AccessDecisionManager

授权器进行授权决策

2. 配置好授权器以后,还需要配置一些投票器来完成投票工作,支持授权的决策过程,具体对资源的安全请求进行一个判断

3. 授权器根据授权规则对投票器提交的投票结果进行汇总判断,得到最后的决策结果,从而完成最终的授权工作,最终决定该用户对HTTP请求所要求的URL资源是否有权限获取

第9章 Spring DM模块的设计与实现 略

第10章 Spring Flex的设计与实现 略