BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 和 ApplicationContext 是 Spring 的两大核心接口, 都可以当做 Spring 的容器. 其中 ApplicationContext 是 BeanFactory 的子接口.
(1)BeanFactory: 是 Spring 里面最底层的接口, 包含了各种 Bean 的定义, 读取 bean 配置文档, 管理 bean 的加载, 实例化, 控制 bean 的生命周期, 维护 bean 之间的依赖关系. ApplicationContext 接口作为 BeanFactory 的派生, 除了提供 BeanFactory 所具有的功能外, 还提供了更完整的框架功能:
1继承 MessageSource, 因此支持国际化.
2统一的资源文件访问方式.
3提供在监听器中注册 bean 的事件.
4同时加载多个配置文件.
5载入多个 (有继承关系) 上下文 , 使得每一个上下文都专注于一个特定的层次, 比如应用的 web 层.
(2)1BeanFactroy 采用的是延迟加载形式来注入 Bean 的, 即只有在使用到某个 Bean 时(调用 getBean()), 才对该 Bean 进行加载实例化. 这样, 我们就不能发现一些存在的 Spring 的配置问题. 如果 Bean 的某一个属性没有注入, BeanFacotry 加载后, 直至第一次使用调用 getBean 方法才会抛出异常.
2ApplicationContext, 它是在容器启动时, 一次性创建了所有的 Bean. 这样, 在容器启动时, 我们就可以发现 Spring 中存在的配置错误, 这样有利于检查所依赖属性是否注入. ApplicationContext 启动后预载入所有的单实例 Bean, 通过预载入单实例 bean , 确保当你需要的时候, 你就不用等待, 因为它们已经创建好了.
3相对于基本的 BeanFactory,ApplicationContext 唯一的不足是占用内存空间. 当应用程序配置 Bean 较多时, 程序启动较慢.
(3)BeanFactory 通常以编程的方式被创建, ApplicationContext 还能以声明的方式创建, 如使用 ContextLoader.
(4)BeanFactory 和 ApplicationContext 都支持 BeanPostProcessor,BeanFactoryPostProcessor 的使用, 但两者之间的区别是: BeanFactory 需要手动注册, 而 ApplicationContext 则是自动注册.
Spring Bean 的生命周期?
首先说一下 Servlet 的生命周期: 实例化, 初始 init, 接收请求 service, 销毁 destroy;
Spring 上下文中的 Bean 生命周期也类似, 如下:
(1)实例化 Bean:
对于 BeanFactory 容器, 当客户向容器请求一个尚未初始化的 bean 时, 或初始化 bean 的时候需要注入另一个尚未初始化的依赖时, 容器就会调用 createBean 进行实例化.
对于 ApplicationContext 容器, 当容器启动结束后, 通过获取 BeanDefinition 对象中的信息, 实例化所有的 bean.
(2)设置对象属性(依赖注入):
实例化后的对象被封装在 BeanWrapper 对象中, 紧接着, Spring 根据 BeanDefinition 中的信息 以及 通过 BeanWrapper 提供的设置属性的接口完成依赖注入.
(3)处理 Aware 接口:
接着, Spring 会检测该对象是否实现了 xxxAware 接口, 并将相关的 xxxAware 实例注入给 Bean:
1如果这个 Bean 已经实现了 BeanNameAware 接口, 会调用它实现的 setBeanName(String beanId)方法, 此处传递的就是 Spring 配置文件中 Bean 的 id 值;
2如果这个 Bean 已经实现了 BeanFactoryAware 接口, 会调用它实现的 setBeanFactory()方法, 传递的是 Spring 工厂自身.
3如果这个 Bean 已经实现了 ApplicationContextAware 接口, 会调用 setApplicationContext(ApplicationContext)方法, 传入 Spring 上下文;
(4)BeanPostProcessor:
如果想对 Bean 进行一些自定义的处理, 那么可以让 Bean 实现了 BeanPostProcessor 接口, 那将会调用 postProcessBeforeInitialization(Object obj, String s)方法. 由于这个方法是在 Bean 初始化结束时调用的, 所以可以被应用于内存或缓存技术;
(5)InitializingBean 与 init-method:
如果 Bean 在 Spring 配置文件中配置了 init-method 属性, 则会自动调用其配置的初始化方法.
(6)如果这个 Bean 实现了 BeanPostProcessor 接口, 将会调用 postProcessAfterInitialization(Object obj, String s)方法;
以上几个步骤完成后, Bean 就已经被正确创建了, 之后就可以使用这个 Bean 了.
(7)DisposableBean:
当 Bean 不再需要时, 会经过清理阶段, 如果 Bean 实现了 DisposableBean 这个接口, 会调用其实现的 destroy()方法;
(8)destroy-method:
最后, 如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性, 会自动调用其配置的销毁方法.
Spring 中 bean 的加载过程?
首先从大的几个核心步骤来去说明, 因为 Spring 中的具体加载过程和用到的类实在是太多了.
(1), 首先是先从 AbstractBeanFactory 中去调用 doGetBean(name, requiredType, final Object[] args, boolean typeCheckOnly[这个是判断进行创建 bean 还是仅仅用来做类型检查] )方法, 然后第一步要做的就是先去对传入的参数 name 进行做转换, 因为有可能传进来的 name="&XXX" 之类, 需要去除 & 符号
(2), 然后接着是去调用 getSingleton()方法, 其实在上一个面试题中已经提到了这个方法, 这个方法就是利用 "三级缓存" 来去避免循环依赖问题的出现的.[这里补充一下, 只有在是单例的情况下才会去解决循环依赖问题]
(3), 对从缓存中拿到的 bean 其实是最原始的 bean, 还未长大, 所以这里还需要调用 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)方法去进行实例化.
(4), 然后会解决单例情况下尝试去解决循环依赖, 如果 isPrototypeCurrentlyInCreation(beanName)返回为 true 的话, 会继续下一步, 否则 throw new BeanCurrentlyInCreationException(beanName);
(5), 因为第三步中缓存中如果没有数据的话, 就直接去 parentBeanFactory 中去获取 bean, 然后判断 containsBeanDefinition(beanName)中去检查已加载的 xml 文件中是否包含有这样的 bean 存在, 不存在的话递归去 getBean()获取, 如果没有继续下一步
(6), 这一步是吧存储在 xml 配置文件中的 GernericBeanDifinition 转换为 RootBeanDifinition 对象. 这里主要进行一个转换, 如果父类的 bean 不为空的话, 会一并合并父类的属性
(7), 这一步核心就是需要跟这个 Bean 有关的所有依赖的 bean 都要被加载进来, 通过刚刚的那个 RootBeanDifinition 对象去拿到所有的 beanName, 然后通过 registerDependentBean(dependsOnBean, beanName)注册 bean 的依赖
(8), 然后这一步就是会根据我们在定义 bean 的作用域的时候定义的作用域是什么, 然后进行判断在进行不同的策略进行创建(比如 isSingleton,isPrototype)
(9), 这个是最后一步的类型装换, 会去检查根据需要的类型是否符合 bean 的实际类型去做一个类型转换. Spring 中提供了许多的类型转换器.
Spring 框架中都用到了哪些设计模式?
(1)工厂模式: BeanFactory 就是简单工厂模式的体现, 用来创建对象的实例;
(2)单例模式: Bean 默认为单例模式.
(3)代理模式: Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术;
(4)模板方法: 用来解决代码重复的问题. 比如. RestTemplate, JmsTemplate, JpaTemplate.
(5)观察者模式: 定义对象键一种一对多的依赖关系, 当一个对象的状态发生改变时, 所有依赖于它的对象都会得到通知被制动更新, 如 Spring 中 listener 的实现 --ApplicationListener.
Spring 事务的实现方式和实现原理
Spring 事务的本质其实就是数据库对事务的支持, 没有数据库的事务支持, spring 是无法提供事务功能的. 真正的数据库层的事务提交和回滚是通过 binlog 或者 redolog 实现的.
(1)Spring 事务的种类:
spring 支持编程式事务管理和声明式事务管理两种方式:
1编程式事务管理使用 TransactionTemplate.
2声明式事务管理建立在 AOP 之上的. 其本质是通过 AOP 功能, 对方法前后进行拦截, 将事务处理的功能编织到拦截的方法中, 也就是在目标方法开始之前加入一个事务, 在执行完目标方法之后根据执行情况提交或者回滚事务.
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码, 只需在配置文件中做相关的事务规则声明或通过 @Transactional 注解的方式, 便可以将事务规则应用到业务逻辑中.
声明式事务管理要优于编程式事务管理, 这正是 spring 倡导的非侵入式的开发方式, 使业务代码不受污染, 只要加上注解就可以获得完全的事务支持. 唯一不足地方是, 最细粒度只能作用到方法级别, 无法做到像编程式事务那样可以作用到代码块级别.
(2)spring 的事务传播行为:
spring 事务的传播行为说的是, 当多个事务同时存在的时候, spring 如何处理这些事务的行为.
1 PROPAGATION_REQUIRED: 如果当前没有事务, 就创建一个新事务, 如果当前存在事务, 就加入该事务, 该设置是最常用的设置.
2 PROPAGATION_SUPPORTS: 支持当前事务, 如果当前存在事务, 就加入该事务, 如果当前不存在事务, 就以非事务执行.'
3 PROPAGATION_MANDATORY: 支持当前事务, 如果当前存在事务, 就加入该事务, 如果当前不存在事务, 就抛出异常.
4 PROPAGATION_REQUIRES_NEW: 创建新事务, 无论当前存不存在事务, 都创建新事务.
5 PROPAGATION_NOT_SUPPORTED: 以非事务方式执行操作, 如果当前存在事务, 就把当前事务挂起.
6 PROPAGATION_NEVER: 以非事务方式执行, 如果当前存在事务, 则抛出异常.
7 PROPAGATION_NESTED: 如果当前存在事务, 则在嵌套事务内执行. 如果当前没有事务, 则按 REQUIRED 属性执行.
(3)Spring 中的隔离级别:
1 ISOLATION_DEFAULT: 这是个 PlatfromTransactionManager 默认的隔离级别, 使用数据库默认的事务隔离级别.
2 ISOLATION_READ_UNCOMMITTED: 读未提交, 允许另外一个事务可以看到这个事务未提交的数据.
3 ISOLATION_READ_COMMITTED: 读已提交, 保证一个事务修改的数据提交后才能被另一事务读取, 而且能看到该事务对已有记录的更新.
4 ISOLATION_REPEATABLE_READ: 可重复读, 保证一个事务修改的数据提交后才能被另一事务读取, 但是不能看到该事务对已有记录的更新.
5 ISOLATION_SERIALIZABLE: 一个事务在执行的过程中完全看不到其他事务对数据库所做的更新.
来源: http://www.bubuko.com/infodetail-3157280.html