springframework
  1. 项目导入IDEA

    环境:Windows,JDK8,Gradle 6.5.1,IDEA 2020.1.3

    • 进入 https://github.com/spring-projects/spring-framework,选择版本5.2.X,下载zip或clone到本地;

    • 编辑项目目录下的build.gradle,全局搜索allprojects,编辑其repositories属性,配置阿里云镜像,如下:

      repositories {
      maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
      maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
      mavenCentral()
      maven { url "https://repo.spring.io/libs-spring-framework-build" }
      }
    • 进入项目根目录下,预编译spring-oxm,在命令行中执行:

      gradlew :spring-oxm:compileTestJava

      (需耐心等待3-5分钟左右…) 成功后打印BUILD SUCCESSFUL

    • 导入项目至idea;

    • 移除spring-aspects模块;

  2. 阅读reference文档

    GA:General Availability,官方正式发布的稳定版本(RELEASE,Stable,Final)

    RC:Release Candidate,发行候选版本,基本不再加入新的功能

    Alpha:内部测试版本,bug较多,功能不全

    Beta:公开测试版本,比Alpha晚些,还会加功能,修bug

    M:Milestone,开发期发行版本,边开发边发行

  3. 单一职责原则

  4. 门面模式 facade pattern

    子系统的外部与其内部的通信必须通过统一的对象进行

    • 提供一个高层次的接口,使得子系统更易于使用
  5. 适配器模式

  6. 泛型

    让数据类型变得参数化

    • 定义泛型时,对应的数据类型是不确定的;
    • 泛型方法被调用时,会指定具体类型;

    核心目标:解决容器类型在编译时安全检查的问题

    • 泛型类

      泛型的参数不支持基本类型

      泛型相关的信息不会进入到运行阶段

      能否在泛型里面使用具备继承关系的类?不可以

      解决办法:

      • 使用通配符 ?,但是会使得泛型的类型检查失去意义;
      • 给泛型加入上边界 ? extends E
      • 给泛型加入下边界 ? super E
    • 泛型接口

    • 泛型方法

      @Data
      public class GenericClassExample<T> {

      /**
      * member这个成员变量的类型为T,T的类型由外部指定
      */
      private T member;

      public GenericClassExample(T member) {
      this.member = member;
      }

      public static <E> void printArray(E[] inputArray) {
      for (E element : inputArray) {
      System.out.printf("%s", element);
      System.out.printf(" ");
      }
      System.out.println();
      }

      public T handleSomething(T target) {
      return target;
      }
      }

      泛型方法中的泛型标识符可独立于泛型类存在的,而泛型类中其他方法受制于泛型标识符的

    • 泛型字母的含义

      • E - Element 在集合中使用,因为集合中存放的是元素;
      • T - Type Java类;
      • K - Key 键;
      • V - Value 值;
      • N - Number 数值类型;
  7. Servlet原理总结

    减少Servlet的数量

    参照SpringMVC,仅通过DispatcherServlet进行请求派发;

    • 拦截所有请求
    • 解析请求
    • 派发给对应的Controller里面的方法进行处理
  8. 简单工厂模式

    定义一个工厂类,根据传入的参数值不同返回不同的实例

    特点:被创建的实例具有共同的父类或接口

    适用场景:

    • 需要创建的对象较少;
    • 客户端不关心对象的创建过程;

    优点:可以对创建的对象进行“加工”,对客户端隐藏相关细节;

    缺点:因创建逻辑复杂或创建对象过多而造成代码臃肿;新增、删除子类均会违反开闭原则;

    开闭原则(待补全)

  9. 工厂方法模式

    定义一个用于创建对象的接口,让子类决定实例化哪一个类

    对类的实例化延迟到子类

    优点:

    • 遵循开闭原则
    • 对客户端隐藏对象的创建细节
    • 遵循单一职责

    缺点:

    • 增加子类的时候“拖家带口”
    • 只支持同一类产品的创建
  10. 抽象工厂

    提供一个创建一系列相关或相互依赖对象的接口

    • 抽象工厂模式侧重的是同一产品族
    • 工厂方法模式更加侧重于同一产品等级

    解决了工厂模式只支持生产一种产品的弊端

    • 新增一个产品族,只需要增加一个新的具体工厂,不需要修改代码;

IOC

Spring IOC容器使用了工厂模式+反射机制

  1. 反射:允许程序在运行时来进行自我检查并且对内部的成员进行操作

    1)作用:

    • 在运行时判断任意一个对象所属的类;
    • 在运行时获取类的对象;
    • 在运行时访问Java对象的属性、方法、构造方法等;

    2)java.lang.reflect 类库里主要的类

    • Field:表示类中的成员变量
    • Method:表示类中的方法
    • Constructor:表示类的构造方法
    • Array:该类提供了动态创建数组和访问数组元素的静态方法

    3)反射依赖的Class

    JVM中只有唯一一个和类相对应的Class对象来描述其类型信息。

    4)获取Class对象的三种方式:

    • Object -> getClass()
    • 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
    • 通过Class类的静态方法:forName(String className) (常用)
    public class ReflectTarget {
    public static void main(String[] args) throws ClassNotFoundException {
    ReflectTarget reflectTarget = new ReflectTarget();
    // 第一种方式获取class对象
    Class reflectTargetClass1 = reflectTarget.getClass();

    // 第二种
    Class reflectTargetClass2 = ReflectTarget.class;
    System.out.println(reflectTargetClass1 == reflectTargetClass2);

    // 第三种
    Class reflectTargetClass3 = Class.forName("demo.reflect.ReflectTarget");
    System.out.println(reflectTargetClass2 == reflectTargetClass3);
    }
    }

    5)获取并操作构造函数

    // 获取所有"公有的"的构造方法
    @CallerSensitive
    public Constructor<?>[] getConstructors() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyConstructors(privateGetDeclaredConstructors(true));
    }

    // 获取所有的构造方法(包括private public default protected)
    @CallerSensitive
    public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyConstructors(privateGetDeclaredConstructors(false));
    }

    // 获取单个的"公有的"构造方法
    @CallerSensitive
    public Constructor<T> getConstructor(Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return getConstructor0(parameterTypes, Member.PUBLIC);
    }

    // 获取某个构造方法(包括private public default protected)
    @CallerSensitive
    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return getConstructor0(parameterTypes, Member.DECLARED);
    }

    // 调用构造方法
    Constructor -> newInstance(Object... initargs)

    // 暴力访问(忽略掉访问修饰符)
    Constructor -> setAccessible(true)

    6)获取并操作成员变量

    // 获取所有的"公有字段" 包含继承字段
    @CallerSensitive
    public Field[] getFields() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyFields(privateGetPublicFields(null));
    }

    // 获取所有字段(包括private修饰的) 不包含继承的字段
    @CallerSensitive
    public Field[] getDeclaredFields() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyFields(privateGetDeclaredFields(false));
    }

    // 获取某个"公有的"字段 包含继承字段
    @CallerSensitive
    public Field getField(String name)
    throws NoSuchFieldException, SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    Field field = getField0(name);
    if (field == null) {
    throw new NoSuchFieldException(name);
    }
    return field;
    }

    // 获取某个字段(可以是私有的) 不包括继承字段
    @CallerSensitive
    public Field getDeclaredField(String name)
    throws NoSuchFieldException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Field field = searchFields(privateGetDeclaredFields(false), name);
    if (field == null) {
    throw new NoSuchFieldException(name);
    }
    return field;
    }

    // 设置字段的值 obj:要设置的字段所在的对象 value:要为字段设置的值
    Field -> public void set(Object obj, Object value);

    7)获取并操作成员方法

    // 获取所有的"公有方法" 包含了父类的方法和Object类
    @CallerSensitive
    public Method[] getMethods() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyMethods(privateGetPublicMethods());
    }

    // 获取所有的成员方法,包括私有的,不包含继承的
    @CallerSensitive
    public Method[] getDeclaredMethods() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyMethods(privateGetDeclaredMethods(false));
    }

    // name:方法名 Class...:形参的Class类型对象
    public Method getMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    Method method = getMethod0(name, parameterTypes, true);
    if (method == null) {
    throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
    }

    @CallerSensitive
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
    if (method == null) {
    throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
    }

    // 调用方法 obj:要调用方法的对象 args:调用方法时传递的实参
    Method -> public Object invoke(Object obj, Object... args);

    8)反射的获取源

    • 用XML来保存类相关的信息以供反射调用;
    • 用注解来保存类相关的信息以供反射调用;
  2. 注解:提供一种为程序元素设置元数据的方法

    元数据是添加到程序元素如方法、字段、类和包上的额外信息。

    1)功能

    • 作为特定的标记,用于告诉编译器一些信息;
    • 编译时动态处理,如动态生成代码;
    • 运行时动态处理,作为额外信息的载体,如获取注解信息;

    2)注解分类

    • 标准注解:Override、Deprecated、SuppressWarnings
    • 元注解:@Retention、@Target、@Inherited、@Documented
    • 自定义注解

    3)元注解

    ​ @Target:注解的作用目标

    ​ @Retention:注解的生命周期

    ​ @Documented:注解是否应当被包含在JavaDoc文档中

    ​ @Inherited:是否允许子类继承该注解

  3. 单例模式(待总结)

    使用反射时恶汉和懒汉模式都不能保证单例,所以采取枚举解决(枚举原理待补全)

  4. 需要实现的点

    • 创建注解

    • 提取标记对象 extractPackageClass

      指定范围,获取范围内的所有类;

      遍历所有类,获取被注解标记的类并加载进容器里;

    • 实现容器

      保存Class对象及其实例的载体

      容器的加载(配置的管理与获取,获取指定范围内的Class对象,依据配置提取Class对象,连同实例一并存入容器)

      容器的操作方式(涉及到容器的增删改查:增加、删除操作,根据Class获取对应实例,获取所有的Class和实例,通过注解来获取被注解标注的Class,通过超类获取对应的子类Class,获取容器载体保存Class的数量)

    • 依赖注入

      • 定义相关的注解标签
      • 实现创建被注解标记的成员变量实例,并将其注入到成员变量里
      • 依赖注入的使用
  5. Spring框架有多种作用域

    singleton

    prototype

    request

    session

    globalsession

  6. IOC源码学习

    配置文件:

    1)根据配置,生成用来描述bean的BeanDefinition,常用属性:

    • 作用范围scope(@Scope)

    • 懒加载lazy-init(@Lazy):决定Bean实例是否延迟加载

    • 首选primary(@Primary):设置为true的bean会是优先的实现类

    • factory-bean和factory-method(@Configuration和@Bean)

      BeanDefinition

      GenericBeanDefinition

      2)术语补充

      组件扫描:自动发现应用容器中需要创建的Bean

      自动装配:自动满足Bean之间的依赖

      3)ApplicationContext常用容器

      传统的基于XML配置的经典容器

      • FileSystemXmlApplicationContext:从文件系统加载配置
      • ClassPathXmlApplicationContext:从classpath加载配置
      • XmlWebApplicationContext:用于Web应用程序的容器

      4)容器的初始化:refresh()

      在已启动的情况下调用refresh()可以清除缓存,重新装载配置信息。

      主要功能:

      • 容器初始化、配置解析
      • BeanFactoryPostProcessor和BeanPostProcessor的注册和激活
      • 国际化配置
      • web内置容器的构造

      模板方法模式:围绕抽象类,实现通用逻辑,定义模板结构,部分逻辑由子类实现

      作用:复用代码,反向控制

      模式涉及的方法种类:模板方法,具体方法,钩子方法,抽象方法

      重要类:AbstractApplicationContext

      5)Resource ResourceLoader 容器之间的关系

      根据资源地址自动选择正确的Resource

      • 自动识别classpath,file等资源地址前缀;
      • 支持自动解析Ant风格带通配符的资源地址;

      Ant:路径匹配表达式,用来对URI进行匹配

      • ? 匹配任何单字符;
      • * 匹配0或者任意数量的字符;
      • ** 匹配0或者更多的目录;

      ResourceLoader:实现不同的Resource加载策略,按需返回特定类型的Resource。

      6)BeanDefinitionReader

      • 读取BeanDefinition
      • BeanDefinitionRegistry
  1. 总结

    1)容器初始化主要做的事情

    容器初始化主要做的事情

  2. 场景问题

    BeanFactory和factoryBean有什么联系和区别

后置处理器PostProcessor

本身也是一种需要注册到容器里的bean

其里面的方法会在特定的时机被容器调用;

实现不改变容器或者bean核心逻辑的情况下对bean进行扩展;

对bean进行包装,影响其行为、修改bean的内容等;

PostProcessor种类

大类分为容器级别的后置处理器以及Bean级别的后置处理器

BeanDefinitionRegistryPostProcessor 容器级别

BeanFactoryPostProcessor 容器级别

BeanPostProcessor bean级别

defaultResourceLoader

Author: Jiayi Yang
Link: https://jiayiy.github.io/2020/07/11/springframework/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.