Spring技术内幕——读书笔记

Spring技术内幕

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

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

两个主要容器:

  1. 实现BeanFactory接口的简单容器系列:实现容器的最基本功能
  2. ApplicationContext:增加了许多面向框架的特性,同时对应用环境作了许多适配

IoC容器的接口设计图:
Spring技术内幕——读书笔记_第1张图片

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技术内幕——读书笔记_第2张图片

BeanDefinition的载入和解析:
对IoC容器来说,这个载入过程,相当于把定义的BeanDefinition在IoC容器中转化为一个Spring内部表示的数据结构的过程,这些BeanDefinition数据在IoC容器中通过一个HashMap来保持和维护。

Spring技术内幕——读书笔记_第3张图片

BeanDefinition在IoC容器中的注册:
DefaultListableBeanFactory中实现了BeanDefinitionRegistry的接口,这个接口的实现完成BeanDefinition向容器的注册,就是把解析得到的BeanDefinition设置到hashMap中去。
Spring技术内幕——读书笔记_第4张图片

IoC容器的依赖注入

什么时候注入:在用户第一次向IoC容器索要bean的时候(lazy-init预实例化除外)
Spring技术内幕——读书笔记_第5张图片

两种实例化Java对象的方法:
- 通过BeanUtils,使用Java反射功能
- 通过CGLIBEnhancer类的create方法

容器初始化和关闭过程

Spring技术内幕——读书笔记_第6张图片

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技术内幕——读书笔记_第7张图片

Advisor通知器
概念:将Advicepointcut结合起来,可以定义应该使用哪个通知在哪个关注点使用。

建立AopProxy代理对象

ProxyFactoryBean:封装了主要代理对象的生成过程,生成方式有两种
- JDK的Proxy
- CGLIB
Spring技术内幕——读书笔记_第8张图片

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);
    }

拦截器调用的实现

JdkDynamicAopProxyinvoke拦截
当Proxy对象的代理方法被调用的时候,JdkDynamicAopProxyinvoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,构造ReflectiveMethodInvocation对象来完成对目标对象方法调用的拦截或者说功能增强。

Cglib2AopProxyintercept拦截
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技术内幕——读书笔记_第9张图片

Spring MVC的设计和实现

DispatcherServlet的处理过程
Spring技术内幕——读书笔记_第10张图片

doDispatch协同模型和控制器的过程
Spring技术内幕——读书笔记_第11张图片

Handler的如何获得
1. 首先会在HttpRequest中取得handler
2. 如果没有,则遍历当前DispatcherServlet持有的所有handlerMapping,返回需要的handler

Spring MVC视图的呈现

DispathcherServletrender

    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

JdbcTemplateexecute实现
Spring技术内幕——读书笔记_第12张图片

JdbcTemplatequery实现
Spring技术内幕——读书笔记_第13张图片

Spring JDBC中RDBMS操作对象的实现

SqlQuery的实现
Spring技术内幕——读书笔记_第14张图片

SqlUpdate的实现
Spring技术内幕——读书笔记_第15张图片

SqlFunction
Spring技术内幕——读书笔记_第16张图片

Spring驱动Hibernate的设计和实现

基本配置Bean
LocalSessionFactoryBean,生成SessionFactory,并对Hibernate中的Session进行管理
Spring技术内幕——读书笔记_第17张图片

Session的管理
Spring对Hibernate Session的管理功能都是由SessionFactoryUtils这个类来提供的。
1. 如果当前线程已绑定事务,Session使用的Connection是当前线程绑定的那个
2. 新建Session和单独使用SessionFactory打开新Session一样,都是使用SessionFactoryopenSession来创建新的Session

Spring驱动iBatis的设计与实现

iBatis操作数据库的主要类
SqlMapClient,类似于Hibernate的Session,是由SqlMapClientFactoryBean在依赖注入完成以后被IoC容器回调afterPropertiesSet中完成创建的。
Spring技术内幕——读书笔记_第18张图片

第6章 Spring事务处理的实现

Spring声明式事务处理

Spring技术内幕——读书笔记_第19张图片

Spring事务处理的设计与实现

事务的创建
Spring技术内幕——读书笔记_第20张图片

事务创建的结果是生成一个TransactionStatus对象,通过这个对象来保存事务处理需要的基本信息,这个是TransactionInfo的一个属性,然后会把TransactionInfo保存在ThreadLocal对象里,这样当前线程可以通过ThreadLocal对象取得TransactionInfo以及与这个事务对应的TransactionStatus对象,从而把处理信息和调用事务方法的当前线程绑定起来。

Spring事务处理

DataSourceTransactionManager的实现
Spring技术内幕——读书笔记_第21张图片

HibernateTransactionManager的实现
Spring技术内幕——读书笔记_第22张图片

第7章 Spring远端调用的实现

Spring HTTP调用器的实现

HTTP调用客户端的实现
Spring技术内幕——读书笔记_第23张图片

HTTP调用器客户端完成远端调用的基本过程:
首先由客户端应用调用代理方法,在调用发生以后,代理类会先运行拦截器,对代理的方法调用进行拦截。在拦截器的拦截行为中,先对本地发生的方法调用进行封装 ,具体来说,就是封装成MethodInvocation对象。然后,把这个MethodInvocation对象,通过序列化和HTTP请求发送到服务器端,在服务器端的处理完成以后,会通过HTTP响应返回处理结果,这个处理结果被风中在RemoteInvocationResult对象中。

HTTP调用服务端的实现
Spring技术内幕——读书笔记_第24张图片

Spring RMI的实现

Spring RMI客户端的实现
Spring技术内幕——读书笔记_第25张图片

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

概述

Spring技术内幕——读书笔记_第26张图片

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的设计与实现 略

你可能感兴趣的:(java)