1 什么是Spring
Spring是一个生态:可以构建java应用所需的一切基础设施.
spring是一个轻量级的开源容器框架,为了解决企业级应用开发的业务逻辑和其他层对象和对象直接的耦合问题.0
Spring是一个IOC和AOP的容器框架
IOC : 控制反转,将new对象的权力由程序员交给Spirng框架控制
AOP :面向切面编程 :对程序无缝增强
容器:包含并管理应用对象的生命周期
2 IOC容器(Bean创建到销毁的整个过程)
ApplicationContext(加载Spirng的上下文)
1 BeanDefinition:读取定义Bean的所有信息,方便后续创建Bean的时候进行传输,Spring的顶层接口(xml中<bean></bean>,@compont,@Configuratiom–@Bean等待)
都是概念态Bean,Bean还没有创建
2 有几个Bean就有几个BeanDefinition,BeanDefinitionMap存储所有的BeanDefinition.
3 循环所有的BeanDefinition,getBean()提取出来 但是ApplicationContext的getBean只是门面方法(直接不做事,交给别人干),其实使用的是BeanFactory的getBean()方法
4 BeanFactory的getBean()方法 负责创建Bean,用到了简单工厂的设计模式,传入一个标识,工厂通过该标识生产对象 getBean
5 applicationContext与BeanFactory的关系
ApplicationContext是BeanFactory的实现类,applicationContext的getBean是一个门面方法,BeanFactory的getBean才是负责生产Bean的,都可以作为容器,但是通常开发应用都是ApplicationContext作为容器的,是因为ApplicationContext提供的功能更加齐全。(例如Spirng的扩展类,环境变量,时间监听器等等)
Bean的生命周期
1 bean的初始化-
——1 通过反射:BeanClass.newInstance()有spring控制实例化过程
2 自己取控制Spring实例化:代理对象 ——-工厂方法,,FactoryBean
FactoryBean :是一个特殊的Bean,如果Bean实现FactoryBean接口就不会将类的本身实例创建为Bean(通过反射),而是FactoryBean.getObject作为当前Bean
bean对象实现FactoryBean,重写getobject(),与getobjectType()方法
getBean的时,不在使用反射,而是factyBean.getObject();
2
Bean属性注入
——
1 出现循环依赖 A bean 初始化后发现需要自动注入B bean,然后初始化B bean,初始化后发现需要自动注入A bean,出现的死循环—解决方法——3集缓存
3 初始化——-BeanpostProcess(Bean的后置加载器)
inint-methid : Bean的生命周期回调的三种方法:1)在@Bean中添加inintMethod
2)使用注解 @PostConstruct
3)实现 initializingBean 接口
Aware接口:
4 销毁 —–
Bean的后置加载器
流程:1 实例化一个applicationContext对象
2 调用Bean工厂后置处理器完成扫描
3 循环解析扫描出库的类信息
4 实例化一个BeanDefintion对象来存储解析出来的信息
5 把实例化好的BeanDefinition对象put到BeanDefinitionMap中缓存起来,以便后面实例化bean;
6 再次调用Bean工厂后置处理器
Spring的优缺点
1 spring的ioc 集中管理了对象,使对象与对象的耦合度降低了,方便维护对象,比如创建一个单例对象,只需要将他配置为一个Bean(Spring Bean对象默认为单例模式)多例模式只需要scop配置为多例,以及懒加载
2 AOP :在不修改代码的情况下可以对业务代码进行增强,避免重复代码,提高了开发效率,方便维护
3 声明事务处理: 提高开发效率,只需要加一个@Transcational
4 方便程序的测试:Spring实现测试,是我们可以结合junit非常方便测试Spring Bean SpringMVC
5 拥有非常强大的粘合度,集成能力非常强,只需要简单的配置,九年集成简单的框架
6 降低了JavaEE api的使用南大:封装很多功能性代码
IOC的优点 :ioc 就是将创建对象的控制权交给Spring的loc,如果需要使用对象需要通过DI(依赖注入)@Autowired 自动注入,就可以使用对象
优点:1集中管理对象,方便维护,2降低耦合度 3 支持加载服务时的饿汉式初始化和懒汉式
springIOC的实现机制
简单工厂 + 反射
简单工厂:一种设计模式 通过一个方法,传入一个标识,生产一个对应的对象(factory.getBean()),但是如果有很多对象,就会有很多标识,所以通过反射来来获取对象,传入的是对象的类的全路径。
IOC与DI的区别是什么
对象是自己创建的 ,bean是Spring容器创建的对象
IOC是控制反转,控制对象的创建权力,解决耦合问题
DI是依赖注入:DI实现了IOC,是IOC中重要的一环
紧耦合和松耦合有什么区别?如何编写松耦合代码
紧耦合 : 是指类之间的高度依赖,如果一个类需要修改,会修改很多其他类
松耦合 : 松耦合是通过促进单一职责和关注点分离,依赖倒置的设计原则来实现
面向对象的三大特性,五大原则
三大特性(封装,继承,多态):
封装
:就是把客观事务封装为一个类,使一些属性与方法被隐藏,对数据的访问只能通过外公开的接口。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
继承
:发成在父子类,子类拥有父类的非私有的属性与方法,使子类具有父类相同的行为。
多态
:同一行为,不同对象有不同的实现方法。发生条件:1)继承 2)重写 3)父类引用指向子类实现。
五大原则(SPR, OCP, LSP, DIP, ISP)
1 单一职责原则SRP(Single Responsibility Principle)
是值一个类功能要单一,不能包罗万象,负责效率不高
2 开放封闭原则OCP(Open-Close Principle)
一个类应该在扩展性上是开放的(可以在此类的基础上,增加功能),而在更改性上的封闭的(封装)
3 里式替换原则LSP(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的所有地方
4 依赖倒置原则DIP(the Dependency Inversion Principle DIP)
依赖于抽象,具体来说就是,高层模块不依赖底层模块,二者都通依赖于抽象。抽象不依赖于具体,而具体依赖于抽象。模块间的依赖是通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;接口或抽象类不依赖于实现类;实现类依赖于接口和抽象类。采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并发引起的风险,提高代码的可读性和可维护性。
5 接口分离原则ISP(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来。
SpirngIOC的加载过程(Bean的创建流程)
bean(概念态—定义态—纯精态—成熟态)
概念态—xml,注解(@compont..),配置类,还未new ApplicationContext 时
定义态 — 通过invokeBeanFactoryPostProcessors(Bean的后置处理器 ),是Spring提供的扩展接口
纯静态–BeanFactory.getBean()依赖注入才能体现纯静态的作用
成熟态–DI 依赖注入
new ApplicationContext(Spring的上下文)
从概念态到定义态的过程
1 实例化一个ApplicationContext对象
2 调用bean工厂后置处理器完成扫描
3 循环解析扫描出来的类信息
4 实例化一个BeanDefinition对象来存储解析出来的信息
5 把实例化好的BeanDefinition对象put到BeanDefinitionMaP中缓存起来的,以便后面的实例化
6 再次其他的Bean工厂的后置处理器
从定义态到纯精态过程
7 spring调用finishBeanFactoryInitialization方法来实例化单例的bean,实例化之前spring要做验证,需要遍历所有扫描出来的类,依次判断这个Bean是否为lazy,是否protorype,是否abstract等
8 在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过反射
9 Spring调用构造方法反射实例化的一个对象,对象以及实例化完成,但是还没有属性注入,纯静态(解决循环依赖问题)
从纯静态到成熟态
10 spring处理合并beanDefinition,然后属性注入
11
初始化
,回调Aware接口,调用生命周期回调方法,如果需要代理完成代理,创建完成
12
创建完成
put到BeanDifinitionMap中(单例池)
什么是Spring Bean?
被Spring IOC管理的对象就是Bean!Bean是一个由Spring IOC实例化,组装,管理的对象
JavaBean : 就是 java 类
配置Bean的几种方法
1 xml <bean class = “com.cp.UserService” id = “”></bean>
2 注解:@Component(controller,@Service,@Repostory)需要在启动类上配置包扫描(component-scan) 反射调用构造方法
3 javaConfig : @Bean
@Bean 与@Component的区别:@Bean可以自己控制实例化过程
4 @import 3种方式
Spring支持几种bean的作用域 : 5种
@scope 单例(singleton),多例(prototype),在web应用中有(request,session,application(一个全局应用共享一个Bean对象))
对象怎么转化为josn数组
ObjcetMapper.writeValueAsString();
将对象转化为Json格式字符串时,会调用get()方法,
将get后面的单词作为key,内容作为value,例如 getxxx(“hy”)—-》 {“xxx“,”hy”}
默认情况下,会将只调用public方法。其他访问修饰符修饰的不可调用
objectMapper.setVisibility(propertyAccessor.Getter,//任何的get方法
JsonAutoDetect.Visibility.ANY //任何的访问修饰符)
单例Bean的优势(单例的设计模式)
1 由于不会每次都创建新的对象所以:减少了新生成实例的消耗,包括Spring通过反射或者cglib生成bean实例。提高了服务器内存的利用率
2 减少JVM垃圾回收的bean实例
3 可以快速获取到bean,因为单例的获取bean操作除了第一次生成之外其余都是从缓存中获取的
Spring的Bean是线程安全的吗
不是,以为Spring创建的Bean默认是单例的,所有当多个进程在进行对Bean属性进行修改时,可以会出现脏读问题,线程不完全。
脏读:当a线程抢占到cpu,修改属性为a时,线程还没有完成,b线程抢占到cpu,将属性修改为b,线程完成并返回属性的值为b,然后线程a进行返回属性业务b
但是,将成员变量声明在方法中,就是线程安全的,或者将Bean修改为多例模式,在就是将成员变量放到ThreadLocal: private ThreadLocal<String> username = new ThreadLocal<>();赋值使用Set,获取使用get,在就是加同步锁,在代码块中添加同步锁(会影响服务器的吞吐量)