当我们的类 A 中引用 B,B 引用 C,C 又引用 A 的时候,这个时候会产生循环依赖。Spring 所解决的循环依赖是有限
定条件的。首先 bean 必须是要单例模式。其次需要通过 get,set 的方式注入才行。使用构造器方式注入和多例模
式都不能解决循环依赖的问题。
根据 Spring 的初始化流程。Spring 先是用构造实例化 Bean 对象 ,此时 Spring 会将这个实例化结束的对象放到一
个 Map 中,并且 Spring 提供了获取这个未设置属性的实例化对象引用的方法。
首先理解为我们先实例化 A,A 此时并没有,于是从一级缓存区中取 A,取不到,然后取二级缓存区中取 A,也取不
到,最后通过对象的匿名工厂方法,创建了一个未装载完毕的实例 A。放入三级缓存区中。然后 B 对象依然与 A 走
了一套相同的流程。C 对象初始化的时候,发现所需要的 A 已经有了,虽然是不完全的,但是也可以用,于是 C 对
象的创建就完善了。放到一级缓存区中。C 对象完善后,B 对象将创建好的 C 对象初始化后,放到一级缓存区中。B
对象也装载完毕,然后 A 对象最后装载完毕。
(1)Spring 框架是一个轻量级的 JavaSE/JavaEE 应用开发框架,是构建企业级应用程序的一站式解决方案。
(2)Spring 是模块化的,并被分为大约 20 个模块(core、beans、context、web 等),允许我们只使用需要的部分,而不需
要引入其他部分。
(3)Spring 的两大核心内容是 IOC 和 AOP(控制翻转和面向切面编程);
谈一下 IOC(Inversion Of Control)
IOC 的意思是控制反转,它是一种设计思想,是一个重要的面向对象编程的法则;
在 Java 开发中,Ioc 可以让我们把设计好的对象交给容器控制,而不是在对象内部直接控制;
对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系;
谈一下 AOP
(1)AOP 被称为面向切面编程,是一种编程范式,是对面向对象编程(OOP)的一种完善。
(2)OOP 最大问题就是无法解耦组件进行开发,而 AOP 就是为了克服这个问题而出现的。
(3)AOP 将整个系统分为"核心业务逻辑"和"非核心的服务";
AOP 的关注点是系统中的“非核心服务”【权限;事务;安全;异常;日志等】;
Spring 将非核心服务封装成一个 AOP 组件,然后通过配置信息形成"核心业务和 AOP 组件"之间的调用关系,
当执行核心业务时,AOP 组件会在合适的时机进行调用
Spring Bean 的生命周期主要分为四个阶段,也就是:Bean 的实例化、Bean 属性赋值、初始化和 Bean 的销毁
其中前三个阶段主要实现在 AbstractAutowireCapableBeanFactory 类中 doCreateBean()方法中;
而"Bean 的销毁"则是容器关闭时;
1.Spring 提供了 “编程式事务” 和 “基于 AOP 方式的声明式事务”
2.Spring 编程式事务管理高层的抽象主要包括三个接口
PlatformTransactionManager:事务管理器
TransactionDefinition:事务定义信息(包括事务的隔离、传播机制等);
TransactionStatus:事务具体运行状态;
其中 Spring 为不同的持久化框架提供了不同事务管理器 PlatformTransactionManager 的接口实现;
比如
使用 Spring JDBC 或 Mybatis 进行持久化数据时的 DataSourceTransactionManager;
使用 Hibernate 进行持久化数据时的 HibernateTransactionManager;
使用 JPA 进行持久化数据时的 JpaTransactionManager;
同时,Spring 可以使用 TransactionTemplate 进行编程式的事务控制;
Spring 基于 AOP 的声明式事务又有三种方式
Spring事务的原理是Aop,进行了切面的增强,那么失效的根本原因是这个AOP不起作用了!
常见的情况有如下几种
1.发生自调用,类里面使用this调用本类的方法(this通常省略),此时这个this对象不是
代理类,而是UserService对象本身!
解决方法很简单,让那个this变成UserService的代理类即可。
2.方法不是public的,@Transaction只能用于public的方法上,否则事务不会生效,如果用在public的方法上,可以开启AspectJ代理模式。
3.数据库不支持事务
4.没有被spring管理
5.异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中
ApplicationContext是BeanFactory的子接口。
依赖关系
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean
的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了
更完整的框架功能:
继承MessageSource,因此支持国际化。
统一的资源文件访问方式。
提供在监听器中注册bean的事件。
同时加载多个配置文件。
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web
层。
加载方式
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才
对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个
属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可
以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预
载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经
创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较
多时,程序启动较慢。
创建方式
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用
ContextLoader。
注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,
但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
默认情况下,Spring 只有在抛出的异常是运行时异常(“非检查型”)时才回滚该事务;
也就是抛出的异常为 RuntimeException 的子类(Errors 也会导致事务回滚);
而抛出非运行时异常(检查型)则不会导致事务回滚;
但是,我们可以明确的配置抛出哪些异常时回滚事务,包括 checked 异常。也可以定义哪些异常抛出时不回滚事务。
拦截器和过滤器都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。
拦截器是基于反射实现,更准确的说是通过 jdk 的动态代理实现; 过滤器是基于函数回调。
拦截器不依赖于 Servlet 容器,过滤器依赖于 Servlet 容器,它属于 Servlet 规范规定的。
拦截器只能对 Controller 请求起作用,过滤器则可以对几乎所有的请求起作用。
拦截器可以访问 controller 上下文的对象(如 service 对象、数据源等),过滤器则不可以访问.
拦截器可以深入的方法前后、异常抛出前后等,并且可以重复调用; 过滤器只在 Servlet 前后起作用,并且只在初始化
时被调用一次.
Java 中的拦截器是基于 Java 反射机制实现的,更准确的划分,应该是基于 JDK 实现的动态代理;
它依赖于具体的接口,在运行期间动态生成字节码。
使用场景:日志记录、权限检查、性能监控、通用行为
Java 中的拦截器是基于 Java 反射机制实现的,更准确的划分,应该是基于 JDK 实现的动态代理;
它依赖于具体的接口,在运行期间动态生成字节码。
使用场景:
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等。
2、权限检查:比如登录检查,进入处理器之前检查是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,
在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如 apache 可以自动记录);
4、通用行为:读取 cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用;
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进
行配置,
在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当
容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该
对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。