zoukankan      html  css  js  c++  java
  • spring1

    课程主题
    spring循环依赖解决问题分析&spring aop核心概念详解&动态代理模式

    课程目标
    1.明白什么是循环依赖?
    2.明白spring中的循环依赖是发生在什么时候?
    3.明白spring中的循环依赖是如何解决的?
    4.spring aop核心概念详解(通知、切面、切入点等等)
    5.要明白aop到底是怎么回事?
    6.要搞明白aop的底层原理是如何结合动态代理去实现的
    7.掌握动态代理的两种方式的写法

    课程回顾
    1.IoC模块3.0版本的改造
    2.spring ioc模块的核心流程的源码阅读。
    * 入口
    * 主流程
    * 涉及到的类

    课程内容
    1.spring循环依赖问题
    * 搞清楚什么是循环依赖
    依赖:引用、成员变量

    ClassA类---->ClassB类 ClassB类--->ClassA类

    依赖注入有两种注入方式:构造方法setter方法注入

    * 循环依赖分为:
    * 构造方法
    * setter方法

    * 循环依赖的例子

    OrderService{
    UserService userService;

    saveOrder(){
    //插入订单表(需要用户名称,而页面只传递一个用户ID)
    //调用UserService去查询用户信息
    }
    }


    UserService{
    OrderService orderService;

    queryOrders(){
    //调用OrderService的服务
    }
    }



    * spring中Bean实例的完整创建流程
    ** Bean的实例化(new)--------此处会反射调用构造器去new对象,所以说此处有可能会发生【构造器循环依赖】
    *** 此处产生的【构造器循环依赖】无法自动解决,只能修改依赖关系或者改为setter方法去依赖。
    OrderService{
    UserService userService;

    public OrderService(UserService userService){
    this.userService=userService;
    }

    saveOrder(){
    //插入订单表(需要用户名称,而页面只传递一个用户ID)
    //调用UserService去查询用户信息
    }
    }

    *** 注意:
    **** 此时从Java本身来说,Bean实例对象已经new 出来了,可以正常使用了。
    **** 但是从Spring来说,该Bean必须完成三个步骤之后,才认为可以被人正常使用。


    ** Bean的属性填充(setter)--------此处会对成员变量调用setter方法去进行依赖注入。----此处可能会发生【setter方法循环依赖】
    *** 其实此时Bean实例已经存在了,只是没有对外暴露使用而已。
    *** Spring的单例Bean被创建成功之后,会放入SingletonObjects的Map集合中,对外暴露使用。
    *** 可以使用缓存的方式去解决循环依赖问题。

    ClassA{
    ClassB
    }
    ClassB{
    ClassA
    }

    二级缓存和三级缓存都是为了处理正在创建中的Bean这个场景的。

    此处例子,是为了说明二级缓存的作用的。
    A---B B---C C---A
    A---C


    创建ClassA的流程
    1.ClassA实例化
    * 如果是单例bean,并且允许引用、该beanname存储到singletonsCurrentlyInCreation(Set集合),那么ClassA对象会提前被暴露给三级缓存保存。
    2.ClassA属性填充---给ClassB类型变量赋值(getBean)
    2.1 ClassB实例化
    2.2 ClassB属性填充---ClassA类型变量赋值(getBean---去ioc容器中找)---
    * 此时去三级缓存中,可以找到该classA对应的ObjectFactory,通过该ObjectFactory获取代理对象获取原对象
    * 换句话说,此处已经找到bean了(只是这个bean还没有完成完成创建,但是bean对象的引用已经获取到了)

    * 如果此时还找不到ClassA,那么又会从第一步开始了,那这样就成死循环了。
    ** 为了不让死循环,那么我们需要此时ClassA的实例被找到
    ** SingletonObjects集合中不存放半成品,所以需要一个新的Map集合来存储半成品(第二级缓存????)
    *** 为了保证提前暴露的对象,和最终的对象是一个,我们需要在获取这个提前暴露的对象的时候,也需要判断是否进行提前代理
    *** 那么这个时候,我们就需要一个第三级缓存。(beanName,获取一个ObjectFactory的工厂类,该类就可以添加产生代理对象的逻辑)
    ***

    * 此时因为ClassA实例已经被new出来(提早暴露的循环引用)
    2.3 ClassB初始化
    2.4 ClassB实例放入SingletonObjects集合中
    3.ClassA初始化
    4.ClassA实例放入SingletonObjects集合中(才是对外暴露的引用集合)

    ** Bean的初始化

    * spring中解决setter方法产生的循环依赖问题是通过三级缓存来解决的?
    ** singletonObjects:第一级缓存
    ***key是beanName
    ***value是成品的Bean实例对象
    ** earlySingletonObjects:第二级缓存
    ***key是beanName
    ***value是半成品的Bean实例对象

    ** singletonFactories:第三级缓存
    ***key是beanName
    ***value是提早产生Bean实例的对象工厂ObjectFactory

    * 三级缓存获取对象的顺序
    * 先从一级缓存中查找
    * 再从二级缓存中查找
    * 最后没有则从三级缓存中获取
    ** ObjectFactory获取对象,有可能获取的是代理对象
    ** 将获取到的对象,【放入二级缓存】,同时删除此beanName对应的三级缓存数据

    * 三级缓存添加对象的顺序
    * 先将第一步new出来的对象,【添加到三级缓存】中的ObjectFactory里面保存。


    * 思考题:
    ** 如果一个目标对象被aop动态加上事务增强功能(代理对象)的话,那么spring容器中存储的是目标对象,还是增强之后的对象,还是都存储?
    *** 答案是spring只会存储一个对象,如果目标对象被AOP产生了代理对象,那么存储的就是代理对象。
    ** aop针对目标对象产生代理对象,是发生在bean创建的哪个流程呢?
    *** 是发生在Bean初始化的过程中,具体说,是发生在Bean调用初始化方法之后,去进行AOP流程。

    2.spring中AOP的核心概念详解
    * AOP:面向切面编程
    * OOP:面向对象编程
    * 结论:AOP可以更好的去补充OOP的缺点。
    * 此处请听录播课

    * AOP作用:可以针对目标对象进行无感知(不修改目标对象的代码的情况下)的【功能增强】。
    * 功能一般分为业务功能和系统功能。
    ** 业务功能:业务操作
    ** 系统功能:事务、日志、安全等
    * AOP可以将业务功能和系统功能进行拆分,专人干专事。
    * AOP是通过哪种方式去实现的无感知功能增强的呢?
    ** 静态织入(了解)
    *** 使用字节码拼接技术,在编译期间,针对目标类对应的class文件进行静态编码(asm)
    ** 动态织入(掌握)
    *** 使用动态代理技术,在运行期间,针对目标对象进行动态代理

    * AOP是一种思路,它的实现产品有多种:AspectJ、Spring AOP、Spring整合AspectJ

    * AOP核心概念分析:
    ** 连接点
    ** 切入点
    ** 目标对象
    ** 代理对象
    ** 通知
    ** 切面/通知器

    ** 引介

    * 代理技术
    ** 静态代理
    *** 在编译期间,为目标类,编写一个代理类,缺点是会编写很多的代理类
    ** 动态代理
    *** 在运行期间,为目标类,利用动态代理技术产生代理对象

    * 动态代理模式
    ** JDK动态代理
    *** 代理对象和目标对象是实现了同一个接口的。
    *** 使用这种代理技术的前提:目标对象必须实现某一个业务接口。
    ** CGLib动态代理
    *** 代理对象是目标对象的子类,它是通过对目标对象实现继承的方式,进行功能增强。
    *** 使用这种代理技术的前提:不需要目标对实现业务接口。
    ** JDK动态代理是Spring默认使用的。

    * JDK动态代理
    ** 产生代理对象流程:Proxy.newProxyInstance();
    *** 1.通过反射可以获取接口的信息,然后由Java来编写代理实现类的源代码(.java文件)
    *** 2.Java来对它自己写的源代码进行编译(API),产生class文件
    *** 3.产生的class文件,需要使用classloader加载到JVM内存中
    *** 4.在JVM中产生代理对象
    ** 代理对象调用流程:InvocationHandler.invoke方法
    *** 根据通知位置编写增强代码
    *** 调用目标对象的方法

  • 相关阅读:
    JS算法练习一
    jquery抖动的按钮
    CSS3教程:box-sizing属性的理解border、padding与容器宽度的关系
    鼠标hover事件
    object 插入元素,插入HTML页面
    点击展开点击收起
    IE支持CSS3圆角
    登录事件,鼠标点击输入框隐藏默认值事件
    复制 动态文本按钮
    凯撒密码、GDP格式化输出、99乘法表
  • 原文地址:https://www.cnblogs.com/BonnieWss/p/12852088.html
Copyright © 2011-2022 走看看