Spring大总结

IOC部分

什么是IOC?

IOC:Inversion of Control,翻译为“控制反转”或“反转控制”,强调的是原来在程序中创建Bean的权利反转给第三方。
例如:原来在程序中手动的去 new UserServiceImpl(),手动的去new UserDaoImpl(),而根据IoC思想的指导,寻求一个第三方去创建UserServiceImpl对象和UserDaoImpl对象。这样程序与具体对象就失去的直接联系。

问:谁去充当第三方角色呢?
工厂设计模式,BeanFactory来充当第三方的角色,来产生Bean实例
问:BeanFactory怎么知道产生哪些Bean实例呢?
可以使用配置文件配置Bean的基本信息,BeanFactory根据配置文件来生产Bean实例

什么是DI?

DI:Dependency Injection,依赖注入,某个Bean的完整创建依赖于其他Bean(或普通参数)的注入。
例如:我们想将UserDao的创建权也反转给BeanFactory,与此同时UserService内部还需要用到UserDao实例对象。DI的做法是,UserService存在于BeanFactory中,UserDao也存在于BeanFactory中,将UserDao在BeanFactory内部设置给UserService的过程叫做“注入”,而UserService需要依赖UserDao的注入才能正常工作,这个过程叫做“依赖注入”。

IOC和DI的关系

  1. IoC强调的是Bean创建权的反转,而DI强调的是Bean的依赖关系,
  2. IoC强调的是Bean创建权的反转,而DI强调的是通过注入的方式反转Bean的创建权,认为DI是IoC的其中一种实现方式。

什么是AOP?

AOP:Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。

什么是Spring?

spring是一个开源的轻量级Java开发应用框架,可以简化企业级应用开发。Spring解决了开发者在JavaEE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。是当前企业中Java开发几乎不能缺少的框架之一。Spring的生态及其完善,不管是Spring哪个领域的解决方案都是依附于在Spring Framework基础框架的。

分析一下Spring的BeanFactory的开发步骤?以及怎样实现DI依赖注入?

开发4步走:
1)导入Spring的jar包或Maven坐标;
2)定义UserService接口及其UserServiceImpl实现类;
3)创建beans.xml配置文件,将UserServiceImpl的信息配置到该xml中;
4)编写测试代码,创建BeanFactory,加载配置文件,获取UserService实例对象。
注入3步走:
1)定义UserDao接口及其UserDaoImpl实现类;
2)修改UserServiceImpl代码,添加一个setUserDao(UserDao userDao)用于接收注入的对象;
3)修改beans.xml配置文件,在UserDaoImpl的中嵌入配置注入;

ApplicationContext与BeanFactory的关系?

首先对ApplicationContext进行介绍:
ApplicationContext 称为Spring容器,内部封装了BeanFactory,比BeanFactory功能更丰富更强大,使用ApplicationContext 进行开发时,xml配置文件的名称习惯写成applicationContext.xml。

关系:

  • BeanFactory是Spring的早期接口,称为Spring的Bean工厂,ApplicationContext是后期更高级接口,称之为Spring 容器;
  • ApplicationContext在BeanFactory基础上对功能进行了扩展,例如:监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
  • Bean创建的主要逻辑和功能都被封装在BeanFactory中,ApplicationContext不仅继承了BeanFactory,而且ApplicationContext内部还维护着BeanFactory的引用,所以,ApplicationContext与BeanFactory既有继承关系,又有融合关系。
  • Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建(延迟加载),而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好。
    在这里插入图片描述

BeanFactory的继承体系
BeanFactory是核心接口,项目运行过程中肯定有具体实现参与,这个具体实现就是DefaultListableBeanFactory,而ApplicationContext内部维护的Beanfactory的实现类也是它。
ApplicationContext的继承体系
Spring基础环境下常用的三个ApplicationContext: (只导入spring-context坐标时)
在这里插入图片描述
Spring的web环境下常用的两个ApplicationContext: (只导入spring-web坐标时)
在这里插入图片描述

基于xml的Spring Bean的配置

在这里插入图片描述

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

如果不配置id,则Spring会把当前Bean实例的全限定名作为beanName.
Bean的配置范围
默认情况下,单纯的Spring环境Bean的作用范围有两个:Singleton和Prototype

  • singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例
  • prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例
留下一个小问题:prototype 与ApplicationContext、懒加载;或者Bean的初始化、实例化与实例创建的关系?

Bean的懒加载
当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的。
Bean的初始化和销毁方法配置
可以通过实现 InitializingBean 接口,完成一些Bean的初始化操作,如下:

public class UserDaoImpl implements UserDao, InitializingBean {
   public UserDaoImpl() {System.out.println("UserDaoImpl创建了...");}
   public void init(){System.out.println("初始化方法...");}
   public void destroy(){System.out.println("销毁方法...");}
   //执行时机早于init-method配置的方法
   public void afterPropertiesSet() throws Exception {
   		System.out.println("InitializingBean..."); 
   }
}

Bean的实例化配置
Spring的实例化方式主要如下两种:

  1. 构造方式实例化:底层通过构造方法对Bean进行实例化
    有参构造在实例化Bean时,需要参数的注入,通过constructor-arg标签,嵌入在bean标签内部提供构造参数

  2. 工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
    工厂方式实例化Bean,又分为如下三种:
    ⚫ 静态工厂方法实例化Bean
    静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其静态方法配置给Spring即可

    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean" factorymethod="getUserDao">
    <constructor-arg name="name" value="haohao"/>
    </bean>
    

    ⚫ 实例工厂方法实例化Bean
    实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean

    <!-- 配置实例工厂Bean -->
    <bean id="userDaoFactoryBean2" class="com.itheima.factory.UserDaoFactoryBean2"/>
    <!-- 配置实例工厂Bean的哪个方法作为工厂方法 -->
    <bean id="userDao" factory-bean="userDaoFactoryBean2" factory-method="getUserDao">
    <constructor-arg name="name" value="haohao"/>
    </bean>
    

    ⚫ 实现FactoryBean规范延迟实例化Bean
    上面不管是静态工厂方式还是非静态工厂方式,都是自定义的工厂方法,Spring提供了FactoryBean的接口规范
    定义工厂实现FactoryBean

    public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {
    	public UserDao getObject() throws Exception {
    		return new UserDaoImpl();
    	}
    	public Class<?> getObjectType() {
    		return UserDao.class;
    	}
    }
    

    配置FactoryBean交由Spring管理即可

    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean3"/>
    

Bean的依赖注入配置(两种方式)
在这里插入图片描述
Bean的自动装配方式
如果被注入的属性类型是Bean引用的话,那么可以在 标签中使用 autowire 属性去配置自动注入方式,属性值有两个:、

  • byName:通过属性名自动装配,即去匹配 setXxx 与 id=“xxx”(name=“xxx”)是否一致;
  • byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错。

基于xml的Spring应用

Spring的getBean()方法

//根据beanName获取容器中的Bean实例,需要手动强转
UserService userService = (UserService) applicationContext.getBean("userService");
//根据Bean类型去容器中匹配对应的Bean实例,如存在多个匹配Bean则报错
UserService userService2 = applicationContext.getBean(UserService.class);
//根据beanName获取容器中的Bean实例,指定Bean的Type类型
UserService userService3 = applicationContext.getBean("userService", 
UserService.class);

Spring配置非自定义的Bean
在实际开发中有些功能类并不是我们自己定义的,而是使用的第三方jar包中的,那么,这些Bean要想让Spring进行管理,也需要对其进行配置。

Bean实例化的基本流程

  1. Spring容器在进行初始化时,会将xml配置的bean信息封装成一个BeanDefinition对象,
  2. 所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,
  3. Spring框架再对该Map进行遍历,使用反射或者调用指定的工厂方法创建Bean实例对象,
  4. 创建好的Bean对象存储在一个名为singletonObjects的Map集合中,
  5. 当调用getBean方法时最终从该Map集合中取出Bean实例对象返回。

xmlbean -> BeanDefinition对象->汇总->beanDefinitionMap->ApplicationContext底层遍历反射,创建Bean实例对象->singletonObjects,Map<String,Object>->get Bean实例(当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回)

DefaultListableBeanFactory对象内部维护着一个Map用于存储封装好的BeanDefinitionMap
Bean实例及单例池singletonObjects, beanDefinitionMap中的BeanDefinition会被转化成对应的Bean实例对象,存储到单例池singletonObjects中去,在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中,维护着singletonObjects。

Spring的后处理器
Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  1. BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行

BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

  1. BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。
·在这里插入图片描述

Spring Bean的生命周期
分为三个阶段:

  • Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断,当前Bean的范围是否是singleton的,是否不是延迟加载的,是否不是FactoryBean,最终将一个普通的singleton的Bean通过反射进行实例化。
  • Bean的初始化阶段:Bean的创建之后还仅仅是个“半成品”,还需要对Bean实例的属性进行填充,执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法,执行自定义初始化init方法等。
    该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等、 spring高频面试题Bean的循环引用问题都是在这个阶段体现的
  • Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池SingletonObjects中去了,即完成了Spring Bean的整个生命周期。

针对生命周期第2个阶段-Spring Bean的初始化过程涉及如下几个过程

  • Bean实例的属性填充

Spring在进行属性注入时,会分为如下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题
    循环依赖解决方案
    Spring 提供了三级缓存存储完整的Bean实例半成品Bean实例,用于解决循环依赖问题。
    UserService和UserDao循环依赖的过程结合上述三级缓存描述一下:
  • UserService实例化对象,但尚未初始化,将UserService存储到三级缓存;
  • UserService属性注入,需要UserDao,从缓存中获取,没有UserDao;
  • UserDao实例化对象,但尚未初始化,将UserDao存储到三级缓存;
  • UserDao属性注入,需要UserService,从三级缓存中获取UserService,UserService从三级缓存中存入二级缓存;
  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
  • UserService注入UserDao;
  • UserService执行其他生命周期,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
public class DefaultSingletonBeanRegistry ... {
	//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
	Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
	//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
	Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
	//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
	Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
  • Aware接口的属性注入
  • BeanPostProcessor的before()方法回调
  • InitializingBean接口的初始化方法回调
  • 自定义初始化方法init回调
  • BeanPostProcessor的after()方法回调

Spring IOC整体流程

在这里插入图片描述

基于注解的Spring应用

基于Bean基本注解开发

基本Bean注解,主要是使用注解的方式替代原有xml的 bean 标签及其标签属性的配置

  1. 可以通过@Component注解的value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写

    //获取方式:applicationContext.getBean("userDao");
    @Component("userDao")
    public class UserDaoImpl implements UserDao {
    }
    //获取方式:applicationContext.getBean("userDaoImpl");
    @Component
    public class UserDaoImpl implements UserDao {
    }
    
  2. 使用注解对需要被Spring实例化的Bean进行标注,但是需要告诉Spring去哪找这些Bean,要配置组件扫描路径。

    <!-- 告知Spring框架去itheima包及其子包下去扫描使用了注解的类 -->
    <context:component-scan base-package="com.itheima"/>
    
  3. 如何配置其他属性(PostConstruct注解的提出)
    在这里插入图片描述

  4. 衍生注解
    在这里插入图片描述

Bean依赖注入注解开发

在这里插入图片描述

@Resource注解存在与 javax.annotation 包中,Spring对其进行了解析

非自定义的Bean注解开发

非自定义Bean不能像自定义Bean一样使用@Component进行管理,非自定义Bean要通过工厂的方式进行实例化,使用@Bean标注方法即可,@Bean的属性为beanName,如不指定为当前工厂方法名称。

//将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource(){
	DruidDataSource dataSource = new DruidDataSource();
	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
	dataSource.setUsername("root");
	dataSource.setPassword("root");
	return dataSource;
}

Bean配置类的注解开发

@Component等注解替代了标签,但是像<import>、<context:componentScan> 等非<bean> 标签怎样去使用注解替代呢?
定义一个配置类替代原有的xml配置文件,标签以外的标签,一般都是在配置类上使用注解完成的.

  1. @Configuration注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,第二个作用是具备@Component作用.
  2. @ComponentScan 组件扫描配置,替代原有xml文件中的<context:component-scan base-package=“”/>
@Configuration
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class ApplicationContextConfig {}

base-package的配置方式:
⚫ 指定一个或多个包名:扫描指定包及其子包下使用注解的类
⚫ 不配置包名:扫描当前@componentScan注解配置类所在包及其子包下的类
  1. @PropertySource 注解用于加载外部properties资源配置
  2. @Import 用于加载其他配置类。
  3. @Primary注解用于标注相同类型的Bean优先被使用权,@Primary 是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的。
  4. @Profile 注解的作用同于xml配置时学习profile属性,是进行环境切换使用的,如@Profile(“test”)

AOP部分

AOP的相关概念

  • 目标对象:target,被增强方法所在的对象
  • 代理对象:Proxy,对目标对象进行增强后的对象,客户端实际调用的对象
  • 连接点:JoinPoint,目标对象中可以被增强的方法
  • 切入点:PointCut,目标对象中实际被增强的方法
  • 通知/增强:Advice,增强部分的代码逻辑
  • 切面:Aspect,增强和切入点的组合
  • 织入:Weaving,将通知和切入点动态组合的过程

用一张图来加深记忆:
在这里插入图片描述

基于xml配置的AOP

配置步骤

  1. 导入AOP相关坐标;
  2. 准备目标类、准备增强类,并配置给Spring管理;
  3. 配置切入点表达式(哪些方法被增强)
  4. 配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)

切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:

execution([访问修饰符]返回值类型 包名.类名.方法名(参数))

其中,
⚫ 访问修饰符可以省略不写;
⚫ 返回值类型、某一级包名、类名、方法名 可以使用 * 表示任意;
⚫ 包名与类名之间使用单点 . 表示该包下的类,使用双点 … 表示该包及其子包下的类;
⚫ 参数列表可以使用两个点 … 表示任意参数。

举例如下:

//表示访问修饰符为public、无返回值、在com.itheima.aop包下的TargetImpl类的无参方法show
execution(public void com.itheima.aop.TargetImpl.show())
//表述com.itheima.aop包下的TargetImpl类的任意方法
execution(* com.itheima.aop.TargetImpl.*(..))
//表示com.itheima.aop包下的任意类的任意方法
execution(* com.itheima.aop.*.*(..))
//表示com.itheima.aop包及其子包下的任意类的任意方法
execution(* com.itheima.aop..*.*(..))
//表示任意包中的任意类的任意方法
execution(* *..*.*(..))

配置类型

AspectJ的通知有以下五种类型
在这里插入图片描述

基于AOP的声明式事务控制

事务是开发中必不可少的东西,使用JDBC开发时,我们使用connnection对事务进行控制,使用MyBatis时,我们使用SqlSession对事务进行控制,缺点显而易见,当我们切换数据库访问技术时,事务控制的方式总会变化,Spring 就将这些技术基础上,提供了统一的控制事务的接口。Spring的事务分为:编程式事务控制声明式事务控制

  1. 编程式事务控制:Spring提供了事务控制的类和方法,使用编码的方式对业务代码进行事务控制,事务控制代码和业务操作代码耦合到了一起,开发中不使用。
  2. 声明式事务控制:Spring将事务控制的代码封装,对外提供了Xml和注解配置方式,通过配置的方式完成事务的控制,可以达到事务控制与业务操作代码解耦合,开发中推荐使用。

Spring MVC

概述

SpringMVC是一个基于Spring开发的MVC轻量级框架,Spring3.0后发布的组件,SpringMVC和Spring可以无缝整合,使用DispatcherServlet作为前端控制器,且内部提供了处理器映射器、处理器适配器、视图解析器等组件,可以简化JavaBean封装,Json转化、文件上传等操作。

在这里插入图片描述

SpringMVC关键组件

在这里插入图片描述
在这里插入图片描述

SpringMVC的请求处理

在这里插入图片描述

  1. 接收普通请求数据,当请求参数的名称与方法参数名不一致时,可以使用@RequestParam注解进行标注

    @GetMapping("/show")
    public String show(@RequestParam(name = "username",required = true) String name, int age){
    	 System.out.println(name+"=="+age);
    	 return "/index.jsp";
    }
    
  2. 接收实体JavaBean属性数据,单个JavaBean数据:提交的参数名称只要与Java的属性名一致,就可以进行自动封装

  3. 接收数组或集合数据,客户端传递多个同名参数时,也可以使用单列集合接收,但是需要使用@RequestParam告知框架传递的参数是要同名设置的,不是对象属性设置的。

  4. 接收数组或集合数据,客户端传递多个不同命参数时,也可以使用Map<String,Object> 进行接收,同样需要用@RequestParam 进行修饰。

  5. 接收Json数据格式数据,Json数据都是以请求体的方式提交的,且不是原始的键值对格式的,所以我们要使用@RequestBody注解整体接收该数据。

     "username":"haohao",
     "age":18,
     "hobbies":["eat","sleep"],
     "birthday":"1986-01-01",
     "address":{
     "city":"tj",
     "area":"binhai"
     }
    }
    
    @PostMapping("/show6")
    public String show6(@RequestBody String body){
    	 System.out.println(body);
    	 return "/index.jsp";
    }
    

请求数据的接受

什么是Rest风格?
Rest(Representational State Transfer)表象化状态转变(表述性状态转变),在2000年被提出,基于HTTP、URI、xml、JSON等标准和协议,支持轻量级、跨平台、跨语言的架构设计。是Web服务的一种新网络应用程序的设计风格和开发方式

Restful风格常用规则

  • 用url表示某个模块名称,资源名称为名词;
    在这里插入图片描述

  • 用请求方式表示模块具体业务动作,例如:GET表示查询、POST表示插入、PUT表示更新、DELETE表示删除。
    在这里插入图片描述
    接收Restful风格数据,Restful请求数据一般会在URL地址上携带,可以使用注解 @PathVariable(占位符参数名称)

    http://localhost/user/100
    
    @PostMapping("/user/{id}")
    public String findUserById(@PathVariable("id") Integer id){
    	 System.out.println(id);
    	 return "/index.jsp";
    }
    

javaweb常用对象的获取(如HttpServletRequest request)

有时在我们的Controller方法中需要用到Javaweb的原生对象,例如:Request、Response等,我们只需要将需要的对象以形参的形式写在方法上,SpringMVC框架在调用Controller方法时,会自动传递实参:

@GetMapping("/javawebObject")
public String javawebObject(HttpServletRequest request, HttpServletResponse response, 
HttpSession session){
	 System.out.println(request);
	 System.out.println(response);
	 System.out.println(session);
	 return "/index.jsp";
}

SpringMVC的响应处理

  1. Spring给客户端响应数据分为两种方式:

    • 传统同步方式:准备好模型数据,在跳转到执行页面进行展示,此方式使用越来越少了,基于历史原因,一些旧项目还在使用;
    • 前后端分离异步方式:前端使用Ajax技术+Restful风格与服务端进行Json格式为主的数据交互,目前市场上几乎都是此种方式了。
  2. 传统同步业务在数据响应时,SpringMVC又涉及如下四种模式:

    • 请求资源转发
    • 请求资源重定向
    • 响应模型数据
    • 直接写回数据给客户端(直接通过方法的返回值返回给客户端的字符串,但是SpringMVC默认的方法返回值是视图,可以通过@ResponseBody 注解显示的告知此处的返回值不要进行视图处理,是要以响应体的方式处理的)
  3. 前后端分离异步业务数据响应

    • 同步方式回写数据,是将数据响应给浏览器进行页面展示的,而异步方式回写数据一般是回写给Ajax引擎的,即谁访问服务器端,服务器端就将数据响应给谁
    • 同步方式回写的数据,一般就是一些无特定格式的字符串,而异步方式回写的数据大多是Json格式字符串。

在讲解SringMVC接收请求数据时,客户端提交的Json格式的字符串,也是使用Jackson进行的手动转换成JavaBean,可以当我们使用了@RequestBody时,直接用JavaBean就接收了Json格式的数据,原理其实就是SpringMVC底层帮我们做了转换,此处@ResponseBody也可以将JavaBean自动给我们转换成Json格式字符串回响应.

@GetMapping("/response5")
@ResponseBody
public User response5() throws JsonProcessingException {
	 //创建JavaBean
	 User user = new User();
	 user.setUsername("haohao");
	 user.setAge(18);
	 //直接返回User对象
	 return user;
}

@ResponseBody和@RestController
可以使用@RestController替代@Controller和@ResponseBody,@RestController内部具备的这两个注解的功能

SpringMVC的拦截器

SpringMVC的拦截器Interceptor规范,主要是对Controller资源访问时进行拦截操作的技术,当然拦截后可以进行权限控制,功能增强等都是可以的。拦截器有点类似 Javaweb 开发中的Filter,拦截器与Filter的区别如下图:
在这里插入图片描述

对比Filter和Interceptor:
在这里插入图片描述
HandlerInterceptor接口方法的作用以及参数、返回值:
在这里插入图片描述
拦截器执行顺序
在这里插入图片描述
当Interceptor1和Interceptor2处于放行,Interceptor3处于不放行时,三个方法的执行顺序如下:
在这里插入图片描述
拦截器执行顺序取决于 interceptor 的配置顺序

SpringMVC异常处理机制

SpringMVC 处理异常的思路是,一路向上抛,都抛给前端控制器 DispatcherServlet ,DispatcherServlet 在调用异常处理器ExceptionResolver进行处理,如下图:
在这里插入图片描述

SpringMVC的异常处理方式

  • 简单异常处理器:使用springmvc内置的异常处理器SimpleMappingExceptionResolver
  • 自定义异常处理器:实现HandlerExceptionResolver接口,自定义异常进行处理
  • 注解方式:使用@ControllerAdvice + @ExceptionHandler来处理

如果全局异常处理器响应的数据都是Json格式的字符串的话,可以使用@RestControllerAdvice替代@ControllerAdvice 和 @ResponseBody

SpringMVC常用的异常解析器
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值