一、Spring框架设计

Spring framework 6大模块

1.1 Spring AOP

AOP: 面向切面编程

Spring 早期版本的核心功能,管理对象声明周期和对象装配

为了实现管理和装配,一个自然的想法就是,加一个中间层代理(字节码增强)来实现所有对象的托管

IoC:控制反转

IoC是一个宽泛的概念,而DI(依赖注入)是其中的一种实现方式。

从对象A直接引入和操作对象B,变成对象A只需要依赖一个接口IB,系统启动和装配阶段,把IB接口的实例对象注入到对象A,这样A就不需要依赖一个IB接口的具体实现。

从而达到修改配置文件,就可以在运行时替换成注入IB接口的其他实现类的一个对象实例。

思考:Spring怎么解决循环依赖?

当实例A依赖B,实例B依赖A时。就构成了循环依赖。Spring解决的思路就是先构造一个"早期"对象,对象的属性还没填充,然后将这个早期对象注入容器。让B完成实例化,此时A就能获取到B的引用,完成了实例化。

具体实现是通过Spring的三级缓存。

什么类型的循环依赖Spring无法处理?

答:双方都是构造函数注入或主bean对象(Spring启动中先加载的对象)使用构造函数注入。

构造器注入和setter注入在创建bean时候的区别

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
///隐藏无用代码
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
} //获取构造器注入
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
} // Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
//如果ctors不为空,就是构造器注入
if (ctors != null) {
return
//需要去创建构造器里依赖的bean,此时还没实例化出对象来放入三级缓存
autowireConstructor(beanName, mbd, ctors, null);
} //不是构造器注入,就可以实例化出一个bean来,并放入三级缓存里面了。
return instantiateBean(beanName, mbd);
}

Spring AOP的实现方式:

动态代理

接口类型,默认使用JDK动态代理。非接口类型默认使用CGlib。

如果接口类型想改为用CBlib动态代理:

spring xml:

<aop:aspectj-autoproxy  expose-proxy="true"    proxy-target-class="true"/>

spring boot 配置文件:

# 增加@EnableAspectJAutoProxy
spring.aop.auto=true
# 开启CGLIB代理
spring.aop.proxy-target-class=true

字节码增强

1.2 Spring Bean

Bean的加载过程:

  1. 创建对象
  2. 属性赋值
  3. 初始化
  4. 注销接口注册
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 实例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
} /**
省略部分代码
**/ // Initialize the bean instance.
Object exposedObject = bean;
try {
//2.属性赋值
populateBean(beanName, mbd, instanceWrapper);
//3.初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
} /**
省略部分代码
**/ // 4.销毁的回调方法
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
} return exposedObject;
}

Bean的初始化过程:

  1. 检查Aware装配
  2. BeanPostProcessors前置处理
  3. init方法
  4. BeanPostProcessors后置处理
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//1.检查Aware接口并设置相关依赖
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//2.BeanPostProcessor前置处理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
//若有init方法,则执行
//若实现了InitializingBean接口,则执行
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcessor后置方法处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

第五周 Spring框架的更多相关文章

  1. 跟着刚哥学习Spring框架--AOP(五)

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  2. 23种设计模式之自定义Spring框架(五)

    7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...

  3. spring框架学习(五)注解

    注解Annotation,是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息.跟注释不同的是,注释是给我们看的,Java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制去读取 ...

  4. OSGI企业应用开发(五)使用Blueprint整合Spring框架(二)

    上篇文章中,我们开发了一个自定义的Bundle,接着从网络中下载到Spring和Blueprint的Bundle,然后复制到DynamicRuntime项目下. 需要注意的是,这些Bundle并不能在 ...

  5. 设计模式(五)——原型模式(加Spring框架源码分析)

    原型模式 1 克隆羊问题 现在有一只羊 tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和 tom 羊 属性完全相同的 10 只羊. 2 传统方式解决克隆羊问题 1) 思路分析(图 ...

  6. 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...

  7. 手写Spring框架,是时候撸个AOP与Bean生命周期融合了!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 嘎小子,这片代码水太深你把握不住! 在电视剧<楚汉传奇>中有这么一段刘邦 ...

  8. Spring 框架的架包分析、功能作用、优点,及jar架包简介

    Spring 框架的架包详解    Spring的作用     Spring的优势  由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...

  9. spring框架详解: IOC装配Bean

    1 Spring框架Bean实例化的方式: 提供了三种方式实例化Bean. 构造方法实例化:(默认无参数) 静态工厂实例化: 实例工厂实例化: 无参数构造方法的实例化: <!-- 默认情况下使用 ...

随机推荐

  1. Linux配置NTP时间服务器(date、hwclock、NTP服务器的配置)

    目录 date命令 hwclock命令 NTP服务的部署 服务端 客户端 date命令 date 命令的作用是查看和设置Linux中的系统日期时间 date                      ...

  2. Linux中环境变量的设置

    目录 环境变量 Shell定义的环境变量 查看环境变量 Linux下环境变量的设置 环境变量 在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软 ...

  3. hdu5249KPI动态中位数(两个set)

    题意(中问题直接粘题意吧)                                                                      KPI Problem Descr ...

  4. .NET Worker Service 如何优雅退出

    上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...

  5. Vue(1):用Vue-cli构建Vue3项目

    使用Vue-cli构建Vue3项目 1.检查node版本 node -v 以上node版本位14.15.0满足Vue3项目的创建条件(Vu3需要node 版本8以上) 为什么需要安装node? vue ...

  6. 关于有符号数和无符号数的转换 - C/C++

    转载自:http://www.94cto.com/index/Article/content/id/59973.html 1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题, ...

  7. Elastic Stack(ElasticSearch 、 Kibana 和 Logstash) 实现日志的自动采集、搜索和分析

    Elastic Stack 包括 Elasticsearch.Kibana.Beats 和 Logstash(也称为 ELK Stack).能够安全可靠地获取任何来源.任何格式的数据,然后实时地对数据 ...

  8. envoy 官方example运行失败问题处理

    镜像内安装包失败处理 方法一:修改Dockerfile,在Dockerfile中增加如下 ubuntu示例 RUN sed -i 's/archive.ubuntu.com/mirrors.aliyu ...

  9. DNS和BIND

    https://www.jianshu.com/p/296b2c7ea76f DNS和BIND 毛利卷卷发关注 0.482018.07.25 10:33:44字数 4,919阅读 4,909 DNS ...

  10. JDK、JRE 和 JVM 的区别

    JDK JDK 是 Java Development Kit 的缩写,JDK 是 Java 语言的软件开发工具包( SDK ).它提供了Java 开发.编译.运行需要的文件和环境. 如果你是 Java ...