什么是Spring
Spring发展到现在已经是一个很完整的生态体系,可以构建java应用所需的一切基础设施.但我们一般说的都是Spring Framework.
核心解释:
-
spring是一个轻量级的开源容器框架.
-
spring是为了解决企业级应用开发的业务逻辑层和其他各层对象和对象的耦合问题
-
spring是一个IOC和AOP的容器框架
- IOC:控制反转
- AOP:面向切面编程
- 容器:包含并管理应用对象的生命周期
Spring的优缺点是什么
优点->从Spring的特性去找
优点
-
方便解耦,简化开发(IOC)
集中管理对象,对象和对象之间的耦合度减低,方便维护对象
-
AOP
不修改代码的情况下可以对业务代码进行增强,减少重复性代码,提高了开发效率,维护方便
-
声明式事务
提高开发效率,只要一个简单的注解@Transactional
-
方便程序的测试
spring实现测试是我们可以结合junit非常方便测试Spring Bean SpringMvc
-
方便集成各种优秀的框架
拥有非常强大的粘合度,集成能力非常强, 只需要简单配置就可以集成第三方框架
-
降低JAVA EE API的使用难度
简化开发,帮我们封装了很多功能性代码
-
Spring源码设计精妙
Spring底层实现大量运用反射,设计模式都值得我们学习,还提供非常多的拓展接口供外部进行扩展
缺点
- 从应用层面来说,没有缺点
- 简化开发,但是要深入底层了解就很困难(上层使用越简单,底层封装就越复杂)
- 由于spring大而全(集成这么多的框架,提供非常多大扩展点,经过多年代码的迭代)代码量很大(一百多万行)学习源码有难度,
IOC 概念?作用?优点?
概念:
IOC:控制反转.
作用:
控制了对象的创建权力,以前由程序员负责对象的创建,现在由Spring的IOC来创建,如果要使用对象,通过DI(依赖注入)@Autowired自动注入就可以使用对象
优点:
- 最小的代价和最小的入侵式使松散耦合得以实现
- IOC容器支持加载服务时的饿汉式初始化和懒加载
IOC的实现机制
简单工厂+反射
简单工厂->BeanFactory.getbean()方法
@SuppressWarnings("all")
public class EasyFactory {
public static BaseService factory(String beanname){
BaseService baseService = null;
//根据方法中传入的形参不同,判断创建不同的实现类
if ("UserServiceimpl".equals(beanname)){
return baseService = new UserServiceimpl();
}
if ("RoleServiceimpl".equals(beanname)){
return baseService = new RoleServiceimpl();
}
return baseService;
}
}
但是随着类的增加,代码也会增加(会有很多if),不方便维护,所以也可以通过反射来创建对象
//形参里面传入的是类的完整路径
public static BaseService factory2(String beanname) throws Exception {
BaseService baseService = null;
//通过加载这个类,然后用反射创建对象
baseService = (BaseService) Class.forName(beanname).newInstance();
return baseService;
}
}
IOC和DI的区别
IOC:解决耦合问题的一种设计思想,设计理念
DI:IOC的实现
紧耦合和松耦合有什么区别
- 紧耦合:
- 紧密耦合是指类之间高度依赖
- 松耦合:
- 松耦合是通过促进单一职责和关注点分离,依赖倒置的设计原则来实现的
BeanFactory的作用
BeanFactory是Spring中非常核心的一个顶层接口
它是Bean的工厂,它的主要职责就是生产Bean
它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean;
它有非常多的实现类,每个工厂都有不同的职责(单一职责)功能,最强大的工厂是DefaultListTableBeanFactory,Spring底层就是使用该实现工厂进行生产Bean的
BeanFactory它 也是个容器 Spring容器(管理着Bean对象的生命周期)
BeanDefinition作用
它主要负责存储Bean的定义信息:决定Bean的生产方式
<bean class="com.entity.User" id="user" scope="singleton" lazy="false" abstract="false" autowire="none" ...>
</bean>
后续BeanFactory根据这些信息就能生产Bean:比如实例化 ,可以通过class进行反射进而得到实例对象
BeanFactory和ApplicationContext的区别
共同点: 都可以作为容器
关系: ApplicationContext实现了FactoryBean
区别:
- FactoryBean中的getBean方法用于生产Bean,优点:内存占用率小,可以用于嵌入式设备
- ApplicationContext实现了FactoryBean,所以它不生产Bean,它只是通知FactoryBean来生产,ApplicationContext的getBean只是一个门面方法,但他做的事情更多:
- 会自动帮我们配置的bean注册进来
- 加载环境变量
- 支持多语言
- 实现事件监听
- 注册很多对外的拓展点
BeanFactory和FactoryBean有什么区别
BeanFactory: 是一个工厂,也就是一个容器,用来生产和管理Bean的
FactoryBean:是一个Bean,所以它也由BeanFactory来管理,不过FactoryBean不是一个普通的Bean,它会表现出工厂模式的样子,是一个能产生或者修饰对象生成的工厂Bean,里面的getObject()方法就是用来获取FactoryBean产生的对象。所以在BeanFactory中使用“&”来得到FactoryBean本身
人话:FactoryBean是一个接口,当一个Bean(类)实现了这个接口,这个Bean就可以通过实现FactoryBean的方法自由返回任意对象。
IOC的容器加载过程
Bean的生产过程:概念态->定义态->纯净态->成熟态
从概念态到定义态的过程
-
实例化一个ApplicaitonContext的对象 (创建一个Spring的容器)
-
调用bean工厂后后置处理器完成扫描
-
循环解析扫描出来的类信息
-
实例化一个BeanDefiniton对象来存储解析出来的信息
-
把实例化好的beanDefinition对象put到beanDefinitionMap中缓存起来,以便后面实例化Bean
-
再次调用其他bean工厂后置处理器
从定义态到纯净态
-
Spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等
-
如果验证完成Spring在实例化一个Bean之前需要推断构造方法,因为Spring实例化对象是通过构造方法反射的,故而需要知道用哪个构造方法;
-
推断完构造方法之后,Spring调用构造方法反射实例化一个对象,注意:这里是实例化对象, 对象, 对象;这个时候对象已经实例化出来了,但是并不是一个完整的Bean,最简单的体现就是这个时候实例化出来的对象属性是没有注入的 ,所以不是一个完整的Bean
从纯净态到成熟态
-
Spring处理合并后端BeanDefinition
-
判断是否需要完成属性注入
-
如果需要完成属性注入,则开始注入属性
初始化
-
判断Bean的类型,回调Aware接口
-
调用生命周期回调方法
-
如果需要代理则完成代理(需要AOP就创建AOP)
创建完成
-
put到单例池——Bean创建完成——存到Spring的容器当中
加载详细图:
什么是Spring的Bean?和对象有什么区别?
Spring官方文档中对SpringBean的定义:
在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。
概念简单明了,我们提取关键信息:
- Bean也是对象,一个或多个限定
- bean由Spring中一个叫IOC的东西管理
Java中的对象:正常使用new关键字创建出来的对象
配置Bean的几种方式
方式 | 格式 |
---|---|
xml | <bean class=“xxx” id=“xxxx” |
注解 | @Component(@Controller,@Service,@Repostory)前提:必须配置扫描包<component-scan> |
javaConfig | @Bean,可以自己控制化过程 |
@import | @import(xxxx.Class) 自己自定义导入Bean |
Spring中支持哪几种Bean的作用域
Spring支持以下五种作用域:
- Singleton: 单例模式,Bean在每个Spring容器中只有一个实例
- Prototype: 多例模式,一个Bean的定义可以有多个实例
- Request: 每次http的请求都会产生一个Bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- Session: 在HTTP Session中,一个Bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- Application: 全局web应用程序范围的范围标识符
注意: 缺省的Spring bean 的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean
会带来很大的性能开销。
Bean的单例模式的好处?
由于每次都会创建新的对象,所以有以下几个性能优势:
- 减少新生成实例的消耗,包括两方面:第一,spring会通过反射或者cglib来生成bean实例,这都是耗性能的操作。其次,给对象分配内存会涉及复杂算法。 提供服务器内存的利用率,减少服务器的内存消耗
- 减少jvm垃圾回收由于不会给每个请求都新生成bean的实例,所以自然回收的对象少了,
- 可以快速获取到Bean因为单例的获取Bean操作除了第一次生成之外,其余都是从缓存中获取,所以很快
Spring中Bean的线程是安全的吗,如果不安全,怎么解决?
Bean的线程是不安全的。
解决方案:
- 把变量创建在方法内
- 把创建Bean的作用域改为多例模式(单例模式线程不安全)
- 方法加上sychnronized关键字
- 使用ThredLocal
实例化Bean有几种方式
- 构造器(反射)
- 静态工厂的方式
factory-method
- 实例工厂的方式(@Bean)
factory-bean
+factory-method
- FactoryBean的方式
### 什么是Bean的装配,什么是Bean的自动装配
装配: 装配是指在Spring容器中把Bean组装在一起,前提是容器需要Bean的依赖关系,如果通过依赖注入把它们装配到一起
自动装配: 在Spring容器中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring容器能够自动装配到相互合作的Bean,这意味着容器不需要配置,能通过Bean工厂自动处理bean之间的协作,这意味着Spring可以通过向Bean Factory中注入的方式自动搞定Bean之间的依赖关系,自动装配可以设置在每个Bean上,也可以设定在特定的Bean上。
自动装配有几种方式:
在xml文件中定义自动装配(Autowired)的方式:
-
no: 默认不进行自动装配,通过手工设置ref属性来进行装配bean。@Autowired 来进行手动指定需要自动注入的属性
-
byName: 通过Bean的名称进行自动装配,如果一个Bean的property和另一个Bean的name相同,则就进行自动装配
-
byType: 通过参数的数据类型进行自动装配
-
constructor: 利用构造函数进行装配,并且构造函数的参数通过byType进行装配
-
autodetect: 自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。 (在spring3.0+弃用)
Bean的生命周期
Bean的生命周期:指的就是Bean从创建到销毁的整个过程:分4大步:
- 实例化
- 通过反射去推断构造函数进行实例化
- 实例工厂,静态工厂
- 属性赋值
- 解析自动装配(byname,bytype,constractor,none @Autowired)DI的体现
- 循环依赖 对象A依赖对象B,对象B又依赖对象A 类似于死锁
- 初始化
- 调用XXXAware回调方法
- 调用初始化生命周期回调(三种)
- 如果bean实现Aop,则创建动态代理
- 销毁
- 在Spring容器关闭的时候进行调用
- 调用销毁生命周期回顾
Bean的生命周期
Bean的生命周期:指的就是Bean从创建到销毁的整个过程:分4大步:
- 实例化
- 通过反射去推断构造函数进行实例化
- 实例工厂,静态工厂
- 属性赋值
- 解析自动装配(byname,bytype,constractor,none @Autowired)DI的体现
- 循环依赖 对象A依赖对象B,对象B又依赖对象A 类似于死锁
- 初始化
- 调用XXXAware回调方法
- 调用初始化生命周期回调(三种)
- 如果bean实现Aop,则创建动态代理
- 销毁
- 在Spring容器关闭的时候进行调用
- 调用销毁生命周期回顾