1.Beanfactory和ApplicationContext有什么区别?
BeanFactory: 可以理解为含有 bean 集合的工厂类。是Spring里面最底层的接口,包含了各种bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。它提供了实例化对象和拿对象的功能。 但它是延迟加载,如果bean没有完全注入,BeanFactory会在你第一次调用GetBean方法才会抛出异常。
ApplicationContext: 应用上下文,继承BeanFactory接口,它是更高级的容器,它在启动的时候就把所有的Bean全部实例化了,可以及时检查依赖是否完全注入。并且在BeanFactory 基础上还提供了其他的功能,如国际化、统一资源文件读取等。
2.BeanFactory 和 FactoryBean 有什么区别?
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。它是一种可以定制实例化Bean的方式,通过实现FactoryBean,完成自定义的Bean实例化细节。例如可以通过FactoryBean代理对象,对其所有方法进行拦截,形成AOP类似功能。
3.Spring的生命周期?
l Bean 容器找到配置文件中 Spring Bean 的定义。
l Bean 容器利用Java Reflection API创建一个Bean的实例。
l 如果涉及到一些属性值,利用set()方法设置一些属性值。
l 如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。
l 如果 Bean 实现了`BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入 ClassLoader对象的实例。
l 类似的,如果实现了其他 *.Aware接口,就调用相应的方法。
l 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization() 方法
l 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
l 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
l 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
l 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
l 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
4.怎么避免循环依赖?
三级缓存
一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean
三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂。
假设A依赖B,B依赖A(注意:这里是set属性依赖)分以下步骤执行:
A依次执行doGetBean、查询缓存、createBean创建实例,实例化完成放入三级缓存singletonFactories中,接着执行populateBean方法装配属性,但是发现有一个属性是B的对象。
因此再次调用doGetBean方法创建B的实例,依次执行doGetBean、查询缓存、createBean创建实例,实例化完成之后放入三级缓存singletonFactories中,执行populateBean装配属性,但是此时发现有一个属性是A对象。
因此再次调用doGetBean创建A的实例,但是执行到getSingleton查询缓存的时候,从三级缓存中查询到了A的实例(早期引用,未完成属性装配),此时直接返回A,不用执行后续的流程创建A了,那么B就完成了属性装配,此时是一个完整的对象放入到一级缓存singletonObjects中。
B创建完成了,则A自然完成了属性装配,也创建完成放入了一级缓存singletonObjects中。
5.Spring IOC如何实现
- 加载并且保存Spring配置文件路径信息然后保存到configLocation中
- 刷新Spring上下文环境
- 创建并且载入DefaultListableBeanFactory(即BeanFactory)
- 根据DefaultListableBeanFactory创建XMLBeanDefinitionReader,用于后面读取xml配置文件信息
- 创建BeanDefinitionDelegate代理类,用于解析xml配置信息
- 解析xml中配置的、、、等不同的标签信息,以便于可以使用不同的解析器进行解析
- 通过XMLBeanDefinitionReader结合location路径信息读取Resources资源信息
- 使用BeanDefinitionDelegate代理类解析Bean元素并且依次进行实例化操作,实例化完毕之后将Bean信息注册(put)到BeanDefinitionMap中以便于可以下次继续使用
6.说说Spring AOP
AOP,即面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
7.Spring AOP实现原理
动态代理;Spring AOP的动态代理主要有两种方式实现,JDK动态代理和Cglib动态代理。JDK动态代理通过反射来接收被代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类。Cglib动态代理的类一般是没有实现接口的类,Cglib是一个代码生成的类库,可以在运行时动态生成某个类的子类,所以,Cglib是通过继承的方式做的动态代理
8.动态代理(Cglib和JDK)
JDK动态代理通过反射来接收被代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类。Cglib动态代理的类一般是没有实现接口的类,Cglib是一个代码生成的类库,可以在运行时动态生成某个类的子类,所以,Cglib是通过继承的方式做的动态代理。如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用Cglib 生成一个被代理对象的子类来作为代理
9.Spring事务实现方式
编程式事务和声明式事务
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务
10.Spring事务底层原理
(1)划分处理单元IOC
IOC 划分了事务处理单元。并且将对事务的各种配置放到了 IOC 容器中(设置事务管理器,设置事务的传播特性及隔离机制)。
(2)AOP拦截需要进行事务处理的类
Spring 事务处理模块是通过 AOP 功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用 TransactionProxyFactoryBean 接口来使用 AOP 功能,生成 proxy 代理对象,通过 TransactionInterceptor 完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取 IOC 容器事务配置属性,转化为 Spring 事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为 TransactionAttribute 表示的数据对象。
(3)对事务处理实现(事务的生成、提交、回滚、挂起)
Spring 委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource 数据源支持、Hibernate 数据源事务处理支持、JDO 数据源事务处理支持,JPA、JTA 数据源事务处理支持。这些支持都是通过设计 PlatformTransactionManager、AbstractPlatforTransaction一系列事务处理的支持。为常用数据源支持提供了一系列的 TransactionManager。
11.如何自定义注解实现功能
(1)自定义注解类的声明
(2)将自定义注解标注在类、方法或者属性上
(3)通过反射来读取注解信息,注解内容与对应的类、方法、属性对应
12.Spring MVC运行流程
(1)客户端(浏览器)发送请求,直接请求到DispatcherServlet。
(2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
(3)解析到对应的Handler(也就是我们平常说的 Controller控制器)后,开始由HandlerAdapter适配器处理。
(4)HandlerAdapter会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
(5)处理器处理完业务后,会返回一个 ModelAndView 对象,Model是返回的数据对象,View是个逻辑上的View。
(6)ViewResolver会根据逻辑View查找实际的View。
(7)DispaterServlet把返回的 Model传给View(视图渲染)。
(8)把 View返回给请求者(浏览器)
13.Spring MVC启动流程
(1)创建根容器。(AnnotationConfigWebApplicationContext)
(2)然后把根容器放入ServletContext中。
(3)接着创建Servlet容器。(也是基于AnnotationConfigWebApplicationContext)
(4)然后使用Servlet容器去创建核心Servlet,即DispacherServlet。
(5)接着把核心Servlet注册到ServletContext中。
(6)接着再注册一些过滤器。
14.Spring的单例实现原理
Spring对Bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是ConcurrentHashMap对象,核心代码是getSingleton(),双重检验锁机制,检查缓存中是否存在实例,如果不存在,则注册到单例注册表中,存在则直接获取。
15.Spring框架中用到了哪些设计模式?
工厂模式、单例模式、代理模式、模板方法、观察者模式、适配器模式