第五周 Spring框架
一、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的加载过程:
- 创建对象
- 属性赋值
- 初始化
- 注销接口注册
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的初始化过程:
- 检查Aware装配
- BeanPostProcessors前置处理
- init方法
- 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框架的更多相关文章
- 跟着刚哥学习Spring框架--AOP(五)
AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...
- 23种设计模式之自定义Spring框架(五)
7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...
- spring框架学习(五)注解
注解Annotation,是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息.跟注释不同的是,注释是给我们看的,Java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制去读取 ...
- OSGI企业应用开发(五)使用Blueprint整合Spring框架(二)
上篇文章中,我们开发了一个自定义的Bundle,接着从网络中下载到Spring和Blueprint的Bundle,然后复制到DynamicRuntime项目下. 需要注意的是,这些Bundle并不能在 ...
- 设计模式(五)——原型模式(加Spring框架源码分析)
原型模式 1 克隆羊问题 现在有一只羊 tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和 tom 羊 属性完全相同的 10 只羊. 2 传统方式解决克隆羊问题 1) 思路分析(图 ...
- 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)
1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...
- 手写Spring框架,是时候撸个AOP与Bean生命周期融合了!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 嘎小子,这片代码水太深你把握不住! 在电视剧<楚汉传奇>中有这么一段刘邦 ...
- Spring 框架的架包分析、功能作用、优点,及jar架包简介
Spring 框架的架包详解 Spring的作用 Spring的优势 由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...
- spring框架详解: IOC装配Bean
1 Spring框架Bean实例化的方式: 提供了三种方式实例化Bean. 构造方法实例化:(默认无参数) 静态工厂实例化: 实例工厂实例化: 无参数构造方法的实例化: <!-- 默认情况下使用 ...
随机推荐
- Linux配置NTP时间服务器(date、hwclock、NTP服务器的配置)
目录 date命令 hwclock命令 NTP服务的部署 服务端 客户端 date命令 date 命令的作用是查看和设置Linux中的系统日期时间 date ...
- Linux中环境变量的设置
目录 环境变量 Shell定义的环境变量 查看环境变量 Linux下环境变量的设置 环境变量 在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软 ...
- hdu5249KPI动态中位数(两个set)
题意(中问题直接粘题意吧) KPI Problem Descr ...
- .NET Worker Service 如何优雅退出
上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...
- Vue(1):用Vue-cli构建Vue3项目
使用Vue-cli构建Vue3项目 1.检查node版本 node -v 以上node版本位14.15.0满足Vue3项目的创建条件(Vu3需要node 版本8以上) 为什么需要安装node? vue ...
- 关于有符号数和无符号数的转换 - C/C++
转载自:http://www.94cto.com/index/Article/content/id/59973.html 1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题, ...
- Elastic Stack(ElasticSearch 、 Kibana 和 Logstash) 实现日志的自动采集、搜索和分析
Elastic Stack 包括 Elasticsearch.Kibana.Beats 和 Logstash(也称为 ELK Stack).能够安全可靠地获取任何来源.任何格式的数据,然后实时地对数据 ...
- envoy 官方example运行失败问题处理
镜像内安装包失败处理 方法一:修改Dockerfile,在Dockerfile中增加如下 ubuntu示例 RUN sed -i 's/archive.ubuntu.com/mirrors.aliyu ...
- DNS和BIND
https://www.jianshu.com/p/296b2c7ea76f DNS和BIND 毛利卷卷发关注 0.482018.07.25 10:33:44字数 4,919阅读 4,909 DNS ...
- JDK、JRE 和 JVM 的区别
JDK JDK 是 Java Development Kit 的缩写,JDK 是 Java 语言的软件开发工具包( SDK ).它提供了Java 开发.编译.运行需要的文件和环境. 如果你是 Java ...