文章目录
- Spring的IOC和AOP机制
- IOC(DI)
- AOP
- Spring AOP 和 AspectJ AOP 有什么区别?
- Spring中Bean的作用域有哪些
- Spring中单例Bean的线程安全问题了解吗
- @Component 和 @Bean 的区别是什么?
- Spring中Bean的生命周期
- SpringMVC的执行流程
- Spring框架中用到了哪些设计模式
- @Transactional(rollbackFor = Exception.class)注解了解吗?
- BeanFactory和ApplicationContext有什么区别?
- 什么是Bean装配
- Spring自动装配Bean有哪些方式
- Spring实现事务的原理
- Spring 管理事务的方式有几种?
- Spring 事务中的隔离级别有哪几种?
- Spring的循环依赖
- Spring事务什么时候会失效
- SpringMVC的工作流程
- SpringBoot自动装配原理
- 如何理解 Spring Boot 中的 Starter
Spring的IOC和AOP机制
我们在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂
主要用到的设计模式有工厂设计模式和代理设计模式
(1)IOC就是典型的工厂模式,通过sessionfactory注入实例
(2)AOP就是典型的代理模式的体现
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息,过滤消息,把消息转发给委托类以及事后处理消息等,代理类与委托类之间通常会存在关联关系,一个代理类对象与一个委托类的对象关联,代理类的对象本身并不是真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务
spring的IOC容器是spring的核心,spring AOP是spring框架的重要组成部分
IOC(DI)
在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来1创建被调用者的实例,但在spring里创建被调用者到的工作不再由调用者来完成,因此被称为控制反转(IOC)
IOC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IOC在其他语言中也有应用,并非 Spring 特有。 IOC容器是 Spring 用来实现 IOC的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
IOC利用了工厂模式,将对象交给容器管理,你只需要再spring配置文件中配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象,在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它以及初始化好的那些bean分配给你需要调用的那些bean的类(假设这个类名为A),分配的方式是调用A的setter方法来注入,而不需要你再A里面new这些bean了
AOP
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
实现AOP的技术,主要分为两大类:
(1)采用动态代理技术,利用截取消息的方法,对该对象进行装饰,以取代原有对象行为的执行。
(2)采用静态织入的方式,引入特定的语法创建"方面",从而使得编译器在编译期间织入有关"方面"的代码。
AOP实现的关键在于代理模式,AOP的代理主要分为静态代理和动态代理。静态代理的代表为AspectJ,动态代理的代表则以SpringAOP为代表
(1)AspectJ是静态代理的增加,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,她会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的是动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB的动态代理
Spring AOP 和 AspectJ AOP 有什么区别?
- Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
- AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单。
- 如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
Spring中Bean的作用域有哪些
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
- application:bean被定义为在ServletContext的生命周期中复用的一个单例对象。
- websocket:bean被定义为在websocket的生命周期中复用的一个单例对象。
- blobal-session:全局作用域。
Spring中单例Bean的线程安全问题了解吗
的确是存在安全问题的。因为,当多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题,即如果Bean时有状态的(有状态的意思就是说有数据存储功能),那么需要开发人员来保证线程安全。 一般情况下,我们常用的 Controller、Service、Dao 这些 Bean 是无状态的。无状态的 Bean 不能保存数据,因此是线程安全的。 常用的解决办法有两种:
- 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
- 改变 Bean 的作用域为
prototype
:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。
@Component 和 @Bean 的区别是什么?
- 作用对象不同:
@Component
注解作用于类,而@Bean
注解作用于方法。 @Component
通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@Component
注解定义扫描的路径从中找出标识了需要装配的类自动装配到Spring的Bean容器中),@Bean
注解通常是我们在标有该注解的方法中定义产生这个Bean,@Bean
告诉了Spring这是某个类的示例,当我需要用的时候把他给我。@Bean
注解比@Component
注解的自定义性更强,而且很多地方我们只能通过@Bean
注解来注册Bean。比如当我们引用第三方库中的类需要装配到 Spring 容器时,则只能通过@Bean
来实现。
Spring中Bean的生命周期
- Bean 容器找到配置文件中 Spring Bean 的定义。
- 如果有多个构造方法,则要推断需要执行哪一个构造方法。
- 确定好构造方法后,进行实例化得到一个对象。
- 对加入了@Autowired注解的对象的属性进行填充。
- 回调Aware方法对Bean容器进行一系列的初始化操作,比如BeanNameAware、BeanFactoryAware。
- 调用BeanPostProcessor的初始化的前方法。
- 调用初始化方法。
- 调用BeanPostProcessor的初始化的后方法,在这里会进行AOP。
- 如果当前创建的Bean是单例的,那么会把Bean放入单例池。
- 程序员使用Bean。
- Spring容器关闭时调用DisposableBean中的destory()方法。
SpringMVC的执行流程
- 用户发送请求至前端控制器
DispatcherServlet
。 -
DispatcherServlet
收到请求调用HandlerMapping
处理器映射器。 - 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给
DispatcherServlet
。 -
DispatcherServlet
调用HandlerAdapter
处理器适配器。 -
HandlerAdapter
经过适配调用具体的处理器(Controller
,也叫后端控制器)。 -
Controller
执行完成返回ModelAndView
。 -
HandlerAdapter
将Controller
执行结果ModelAndView
返回给DispatcherServlet
。 -
DispatcherServlet
将ModelAndView
传给ViewReslover
视图解析器。 -
ViewReslover
解析后返回具体View
。 -
DispatcherServlet
根据View
进行渲染视图(即将模型数据填充至视图中)。 -
DispatcherServlet
响应用户。
Spring框架中用到了哪些设计模式
- 工厂设计模式 : Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 - 代理设计模式 :Spring AOP 功能的实现。
- 单例设计模式 :Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 - 包装器设计模式 :我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式:Spring 事件驱动模型就是观察者模式很经典的一个应用,Spring中Observer(观察者模式)最常用的地方就是Listener监听器。
- 适配器模式 :Spring定义了一个适配器接口,使得每一种Controller都有一种对应的适配器实现类,让适配器代替Controller执行相应的方法,这样在拓展Controller时,只需增加一个适配器类就完成了SpringMVC的拓展了。
- 装饰器模式:动态地给一个对象添加一些额外的职责,Spring中用到的包装器模式在类名上有两种表现:一种时类名中含有Wrapper,另一种时类名中含有Decorator。
- 策略模式:Spring框架的资源访问Resource接口,该接口提供了更强的资源访问能力。Spring框架本身大量使用了Resource接口来访问底层资源。
@Transactional(rollbackFor = Exception.class)注解了解吗?
Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
当@Transactional
注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
在@Transactional
注解中如果不配置rollbackFor
属性,那么事务只会在遇到RuntimeException
的时候才会回滚,加上rollbackFor=Exception.class
,可以让事务在遇到非运行时异常时也回滚。
BeanFactory和ApplicationContext有什么区别?
BeanFactory
和ApplicationContext
是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
- BeanFactory是Spring中最底层的接口,包含了各种Bean的定义、读取配置文件、管理Bean的加载、Bean的实例化、控制Bean的生命周期,维护Bean之间的依赖。ApplicationContext接口作为BeanFactory的派生,除了具有BeanFactory所具有的功能外,他还具有其他功能:支持国际化、统一资源文件的访问方式、同时加载多个配置文件。
- BeanFactory时采用延迟加载的形式来注入Bean的,即只有在某个Bean时(调用getBean()),才对该Bean进行加载实例化, 这样我们就不能发现一些spring存在的配置问题,如果Bean的某一个属性没有注入,BeanFactory加载后直到第一次调用getBean方法才会抛出异常。
- ApplicationContext它是在容器启动的时候,一次性创建了所有的Bean,这样在容器启动的时候,我们就可以发现Spring中存在的配置错误,这样有利于检查依赖属性是否注入。ApplicationContext启动后会预载入所有的单实例Bean,通过预载入单实例的Bean,确保你在需要的时候,可以不需要等待,直接取用。
- 相对于BeanFactory,ApplicationContext唯一的不足时占用内存,当应用程序配置的Bean较多的时候,程序启动会比较慢。
- BeanFacotry通常是以编程的方式被创建的,而ApplicationContext还可以以声明的方式来创建,比如说ContextLoader。
- BeanFactory和ApplicationContex都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但是两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
什么是Bean装配
装配是指在Spring容器中把bean组装在一起。 在Spring框架中,在配置文件设定bean依赖关系是一个很好的机制,Spring容器可以自动装配互相合作的bean,这样意味着容器不需要配置就能够通过Bean工厂发自动处理Bean之间的协作。
Spring自动装配Bean有哪些方式
在Spring的配置文件中共有五种自动装配:
- no:默认的方式是不通过自动装配,通过手动ref属性来进行装配Bean。
- byName:通过Bean的名称进行自动装配,如果一个Bean的property与另一个Bean的name相同,就会进行自动装配。
- byType:通过参数的数据类型进行自动装配。
- constructor:通过构造函数进行自动装配,并且构造函数的参数也是通过byType进行装配的。
- autodetect:自动探测,如果有构造方法就是使用construct的方式自动装配,否则使用byType的方式自动装配。
Spring实现事务的原理
在使用Spring框架时,可以有两种使用事务的方式,一种是编程式事务,另一种是声明式事务,@Transaction注解就是声明式事务。
首先事务的概念是在数据库层面的,Spring只是基于数据库中的事务进行了拓展,以及提供了一些能让程序员更既方便操作事务的方式。比如我们可以在某个方法上增加@Transaction注解,开启事务,这个方法中的所有sql都会在一个事务中执行,统一成功或者统一失败。
在一个方法上加了@Transaction注解后,Spring会基于这个类生成一个代理对象,会将这个这个代理对象作为bean,在当使用这个代理对象的方法时,如果中国方法上存在@Transaction注解,那么代理逻辑会把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行的业务逻辑没有出现异常,那么代理逻辑中就会将事务进行提交,如果执行的业务逻辑方法出现了异常,那么会将事务进行回滚。
针对哪些异常回滚事务是可以配置的,可以利用@Transaction注解中的rollbackFor属性进行配置,默认会对RuntimeException和Error进行回滚。
Spring 管理事务的方式有几种?
- 编程式事务:在代码中硬编码。(不推荐使用)
- 声明式事务:在配置文件中配置。(推荐)
- 基于XML的声明式事务
- 基于注解的声明式事务
Spring 事务中的隔离级别有哪几种?
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,MySQL采用REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取未提交的数据,可能会导致脏读、幻读、不可重复读。
- TransactionDefinition.ISOLATION_READ_COMMITTED:允许去读并发事务已提交的数据,可以阻止脏读,但是幻读或者不可重复读可能发生。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:对同一个字段多次读取结果都是一致的,除非数据时被本身事务自己所修改,可以阻止脏读和不可重复读,但是幻读仍然可能发生。
- TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔离级别1,完全服从ACID的隔离级别,所有事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
Spring的循环依赖
- A创建过程中需要B,于是A将自己放到三级缓存中,去实例化B。
- B实例化的时候发现需要A,于是B先去查一级缓存,发现找不到,然后去查二级缓存,还是没有,接着再去找三级缓存,找到了A,于是把三级缓存里面的这个A放到二级缓存中,并删除三级缓存里面的A。
- B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中的状态),然后接着回来创建A,此时B已经创建结束,直接从一级缓存中拿到B,然后完成创建,并将A自己放到一级缓存里面。
Spring事务什么时候会失效
- 发生自调用。
- 方法不是public的,@Transaction只能用于public方法,否则事务会失效,如果要用到非public方法上,可以开启AspectJ代理模式。
- 数据库不支持事务的。
- 没有被Spring管理的。
- 异常被catch了,事务不会回滚。
SpringMVC的工作流程
- 客户端(浏览器)发送请求,直接请求到 DispatcherServlet。
- DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
- 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
- HandlerAdapter 会根据 Handler来调用真正的处理器开始处理请求,并处理相应的业务逻辑。
- Handler处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet。
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
- ViewReslover解析后返回具体View。
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
- DispatcherServlet响应用户。
SpringBoot自动装配原理
如何理解 Spring Boot 中的 Starter
比如传统使用spring springmvc,如果需要引入mybatis等框架,需要到xml中定义mybatis需要的bean。
stater就是定义一个start的jar包,写一个@Configuration配置类,将这些bean定义在里卖弄,然后在start包的META-INF/spring.factories中写入该配置类,springboot会按照约定来加载该配置类。
开发人员只需要将相应的start包依赖引入到应用,然后进行相应的属性配置,也有默认的配置,就可以直接进行代码的开发了。