Servlet和Spring的面试总结

JSP

jsp和servlet的区别和联系:

1.jsp经编译后就变成了Servlet.
(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)
2.jsp更擅长表现于页面显示,servlet更擅长于逻辑控制.
3.Servlet中没有内置对象,Jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到.
Jsp是Servlet的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,Jsp中的Java脚本如何镶嵌到一个类中,由Jsp容器完成。
而Servlet则是个完整的Java类,这个类的Service方法用于生成对客户端的响应。

联系:
JSP是Servlet技术的扩展,本质上就是Servlet的简易方式。JSP编译后是“类servlet”。

Servlet和JSP最主要的不同点在于:
Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。
而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。
JSP侧重于视图,Servlet主要用于控制逻辑
Servlet更多的是类似于一个Controller,用来做控制。

servlet

用java编写的服务器端程序, 运行在web服务器,servlet和客户端通信

采用"请求/响应"模式

servlet作用

​ 接收客户端请求 service

​ 处理 :调用其他的java程序处理请求

​ 响应: 将处理的结果返回给客户端

服务器负责 客户端 与 servlet之间的通信

servlet的运行流程

(1)浏览器发送请求到服务器, 服务器负责接收请求

(2)服务器调用某一个Servlet来处理请求, (在此期间可能需要Servlet访问数据库) , 最后得出请求处理的结果

(3)将处理的结果写入JSP或者HTML中, 由服务器负责将页面响应给浏览器
因此, Servlet的作用是服务器端的一个Java程序, 负责处理请求!!

request对象

Request对象的三大特征:
(1)生命周期:一次请求开始时创建Request对象, 一次请求结束时销毁request对象。
(2)作用范围:一次请求范围内。
(3)主要功能: 通过请求转发+域对象实现带数据到目的地

request和response区别

其实从字面上我们就可以知道他们俩的区别在于一个是请求(request),而另一个是响应(response),servlet作为服务端,请求便是来自浏览器的请求,响应便是服务器对浏览器的响应。在你想获取浏览器请求的数据时,我们就要用request,而在我们要向浏览器响应数据或页面时,我们就要用到response。

request 是请求的载体,它附带着,请求的参数,ip,cookie,表单,字符编码,或者上传文件。你可以通过request去获得你所需要的信息。

response是响应的载体,你可以设置,表头,报文,响应文件类型,字符编码,response,自带一个输出流,当你需要将一个页面或者一个文件传到客户端时,你可以通过这个流来进行操作

生命周期

服务器启动时创建/第一次访问时创建

init() 初始化

服务 service() doget/dopost -----> springmvc解析—> 方法

销毁 destroy()

servlet是线程安全的吗

不安全,servlet对象是单例的, 成员变量会被多个线程共享, 解决方法:使用ThreadLocal

请求转发的特点:

(1)转发前后地址栏地址不会发生变化

(2)请求转发是一次请求,一次响应

(3)转发只能是同一个Web应用内的资源互相转发, 不可以是不同的Web应用之间的资源进行转发。

请求重定向特点:

(1)两次请求, 两次响应

(2)重定向前后地址栏地址都会发生变化。

(3)重定向可以在同一个Web应用内部的资源之间进行跳转,也可以在不同的Web应用或者不同的主机之间进行跳转

过滤器

对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理,通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理

过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法

应用场景
自动登录
统一设置编码格式
访问权限控制
敏感字符过滤等

JSP

JSP脚本中包含9个内置对象:

1.out向客户端输出

2.request 封装用户请求

3.response 向用户做出响应

4.session 客户和服务器间的会话

5.application 于服务器启动时开始运行,用来存放全局变量,在用户间共享

6.pageContext 用于访问page的各种对象

7.exception 异常

8.config 初始化要用的参数

9.page JSP页面本身

AJAX

Ajax 全称为:“Asynchronous JavaScript and XML”(异步 JavaScript和 XML),使用 Ajax,我们可以无刷新状态更新页面,并且实现异步提交,提升了用户体验。

同步

目前与服务器端的交互方式是同步,当客户端与服务器交互时,客户端就不能进行其他操作,只能等待服务器端的响应,会刷新页面.

异步(不同步):

当客户端正在进行正常操作时,还可以同时与服务器进行交互,服务器向客户端响应信息,将信息更新到网页局部,整个过程页面不刷新.

JSON 键值对是用来保存 JS 对象的一种方式,和 JS 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:

重定向

1、请求次数

重定向是浏览器向服务器发送一个请求并收到响应后再次向一个新地址发出请求,转发是服务器收到请求后为了完成响应跳转到一个新的地址;重定向至少请求两次,转发请求一次;

2、地址栏不同

重定向地址栏会发生变化,转发地址栏不会发生变化;

3、是否共享数据

重定向两次请求不共享数据,转发一次请求共享数据(在request级别使用信息共享,使用重定向必然出错);

4、跳转限制

重定向可以跳转到任意URL,转发只能跳转本站点资源;

5、发生行为不同

重定向是客户端行为,转发是服务器端行为;

框架

mybatis

什么是Mybatis?

一个优秀的(半自动的)数据持久层框架,是一个将sql与java分离的,提供对象关系映射(ORM),开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement 等繁杂的过程。

将JDBC中的接口进行了封装,简化了JDBC代码. 提供了动态sql语句使得功能强大.

ORM是什么

ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

Mybaits的优缺点

优点:

1.sql语句与代码分离,存放于xml配置文件中

2.用逻辑标签控制动态SQL的拼接

3.查询的结果集与java对象自动映射,保证n名称相同,配置好映射关系即可自动映射或者

4.编写原生SQL 效率高

缺点:

JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试

对 SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦(相比hibernate) 配置方言oracle

Hibernate 和 MyBatis 的区别

相同点

都是对jdbc的封装,都是持久层的框架,都用于dao层的开发。

不同点

映射关系

MyBatis 是一个半自动映射的框架,配置Java对象与sql语句执行结果的对应关系,多表关联关系配置简单
Hibernate 是一个全表映射的框架,配置Java对象与数据库表的对应关系,多表关联关系配置复杂

MyBatis编程步骤是什么样的?

1、 创建SqlSessionFactory

2、 通过SqlSessionFactory创建SqlSession

3、 通过sqlsession执行数据库操作

4、 调用session.commit()提交事务

5、 调用session.close()关闭会话

简述Mybatis的运行流程

第一步:通过Resources加载配置好的mybatis.xml配置文件.

第二步:构建会话工厂,new了一个SqlSessionFactoryBuilder对象,我们调用了他的**build()**方法.

第三步:创建会话对象,通过SqlSessionFactory生成SqlSession

第四步:jdk动态代理生成mapper接口的代理对象.

第五步:通过代理对象的方法调用mapper方法最终执行的方法.

第六步: 封装查询结果.

Mybatis核心类:

SqlSessionFactory:
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或通过Java的方式构建出 SqlSessionFactory 的实例。SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,建议使用单例模式或者静态单例模式。一个SqlSessionFactory对应配置文件中的一个环境(environment),如果你要使用多个数据库就配置多个环境分别对应一个SqlSessionFactory。

SqlSession:
SqlSession是一个接口,它有2个实现类,分别是DefaultSqlSession(默认使用)以及SqlSessionManager。SqlSession通过内部存放的执行器(Executor)来对数据进行CRUD。此外SqlSession不是线程安全的,因为每一次操作完数据库后都要调用close对其进行关闭,官方建议通过try-finally来保证总是关闭SqlSession。

Executor:
Execounterrevolutionary接口有两个实现类,其中BaseExecutor有三个继承类分别是BatchExecutor(重用语句并执行批量更新),ReuseExecutor(重用预处理语句prepared statement,跟Simple的唯一区别就是内部缓存statement),SimpleExecutor(默认,每次都会创建新的statement)。以上三个就是主要的Executor。通过下图可以看到Mybatis在Executor的设计上面使用了装饰器模式,我们可以用CachingExecutor来装饰前面的三个执行器目的就是用来实现缓存。

#{}和${}的区别是什么?

#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。

Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。

#{} 可以有效的防止SQL注入,提高系统安全性;${} 不能防止SQL 注入

MyBatits的resultType和resultmap的区别?

resultmap 自定义映射 列名与类中属性名不相同, 关联关系(单个,集合)

resultType 具体的返回结果类型

使用 MyBatis 的 mapper 接口调用时有哪些要求

接口中的方法 与 xml中 匹配

方法名与 xml中id名相同

参数类型 与 xml中参数类型相同

返回值 与 xml中返回值相同

方法能重载 不能重载

什么是MyBatis的接口绑定?

接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们通过代理对象调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。

Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?

Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。

其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。

Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 把一个关联查询 ,拆分为多次查询,需要时,在发出查询,嵌套查询

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

Mybatis的一级、二级缓存

(1)一级缓存: 其存储作用域为SqlSession,当 SqlSession.flush 或 close 之后,该 SqlSession中的所有 Cache 就将清空,默认打开一级缓存。

(2)二级缓存与一级缓存其机制相同,其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache .要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;

当配置了二级缓存后,关闭sqlSession时会将数据写入到二级缓存,下次在新会话中仍然可以从二级缓存中查询到数据.

使用MyBatis的mapper接口调用时有哪些要求

  1. Mapper接口方法名和mapper.xml中定义的每个sql的id相同。
  2. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相
    同。
  3. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
  4. Mapper.xml文件中的namespace即是mapper接口的类路径。

这个Dao接口的工作原理是什么

Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。

Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

举例:select * from student,拦截sql后重写为:select t.* from (select * from student) t limit 0, 10

springmvc与springboot的联系和区别:

​ 联系:

​ Spring最初利用工厂模式(DI)和代理模式解耦应用组件,为了解耦开发了springmvc;而实际开发过程中,经常会使用到注解,程序的样板很多,于是开发了starter,这套就是springboot。

​ 区别:

​ 1.springboot是约定大于配置,可以简化spring的配置流程;springmvc是基于servlet的mvc框架,个人感觉少了model中的映射。

​ 2.以前web应用要使用到tomat服务器启动,而springboot内置服务器容器,通过@SpringBootApplication中注解类中main函数启动即可。

spring

springmvc与springboot的联系和区别:

    联系:

     Spring最初利用工厂模式(DI)和代理模式解耦应用组件,为了解耦开发了springmvc;而实际开发过程中,经常会使用到注解,程序的样板很多,于是开发了starter,这套就是springboot。

    区别:

   1.springboot是约定大于配置,可以简化spring的配置流程;springmvc是基于servlet的mvc框架,个人感觉少了model中的映射。

   2.以前web应用要使用到tomat服务器启动,而springboot内置服务器容器,通过@SpringBootApplication中注解类中main函数启动即可。

Spring 框架中都用到了哪些设计模式?

  1. 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
  2. 单例模式:Bean默认为单例模式。
  3. 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
  4. 模板方法:用来解决代码重复的问题。比如.RestTemplate, JmsTemplate, JpaTemplate。
  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的
    对象都会得到通知被制动更新,如Springlistener的实现–ApplicationListener。

优点

开源的,轻量级的(Spring的组件代码),非侵入式的一站式框架,简化企业级应用开发。方便解耦,简化开发

IOC就是控制反转(就是将原本由程序代码直接操作的对象的调用权交给容器),目的是为了减低计算机代码的耦合度,所谓的耦合度就是代码中的逻辑关系不要太紧密,避免后面改的人会因为不懂业务逻辑导致改错代码;除此之外也避免我们每次创建新的对象,减少对应的代码量。我们实际代码过程中最常见的方式是依赖注入(DI Dependency Injection),所谓依赖注入就是通过构造注入或者set进行注入。依赖查找(DL Dependency Lookup)这是通过名称和类型查找bean。

面向切面(AOP),利用它可以很容易实现一些拦截,如事务控制等。可以把一些独立的功能抽取到一个切面中去,在不改变原来代码的基础上对我们的代码进行功能上的增强。

​ Spring对于主流的应用框架提供了很好的支持,例如mybatis

​ Spring提供自己的MVC实现。

缺点

 配置是重量级的(配置很麻烦,“废话”很多,例如配置开启事务(事务在现在的项目中是必要的)、开启注解等 。虽然Spring引入了注解功能,但是仍然需要编写大量的模板化配置文件。

​ 项目的依赖管理比较麻烦(jar包相关吗,需要的jar包如:数据库,gson,日志,spring相关,阿里数据源,mybatis,文件上传组件),需要分析要导入大量库的坐标,而且还需要分析导入与之有关依赖,一旦选择错依赖版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

​ Spring Boot对上述Spring的缺点进行改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。

​ Spring依赖反射,反射影响性能

Spring 框架中都用到了哪些设计模式

  1. 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
  2. 单例模式:Bean默认为单例模式。
  3. 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
  4. 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

IOC

什么是Spring IOC 容器?实现原理就是工厂模式加反射机制

控制反转即IOC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。

Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。

IOC的优点:

  1. IOC 或 依赖注入把应用的代码量降到最低。
  2. 它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
  3. 最小的代价和最小的侵入性使松散耦合得以实现。
  4. IOC容器支持加载服务时的饿汉式初始化和懒加载。

什么是Spring的依赖注入

即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系

依赖注入方式 xml 注解

@Component, @Controller, @Repository, @Service 有何区别?

@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。

@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。

@Service:您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。

@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为SpringDataAccessException。

@Required 注解有什么作用

这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。

@Autowired 注解有什么作用

@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required
属性为false)。@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用
法和@Required一样,修饰 setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。

@Autowired和@Resource之间的区别

@Autowired可用于:构造函数、成员变量、Setter方法

@Autowired和@Resource之间的区别

@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

@Qualifier 注解有什么作用

当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。

@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。

此注释可应用于两个级别:

类级别:映射请求的 URL

方法级别:映射 URL 以及 HTTP 请求方法

AOP

AOP核心概念

  1. 切面 (Aspect)
    类是物体特征的抽象,切面就是对横切关注点的抽象
  2. 横切关注点
    对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
  3. 连接点
    被拦截到的点,因为Spring只支持方法类型的连接点,所以Spring中连接点指的就是被拦截到的方
    法,实际上连接点还可以是字段或者构造器
  4. 切入点
    对连接点进行拦截的定义
  5. 通知
    指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知5类
  6. 目标对象
    代理的目标对象
  7. 织入
    将切面应用到目标对象并导致代理对象创建的过程
  8. 引入
    在不修改代码前提下,引入可以在运行期为类动态添加一些方法或字段

AOP 通知类型

1.前置通知
在目标方法被调用之前调用通知功能:在某连接点之前执行的通知,但这个通知不能阻止连接点之
前的执行流程(除非它抛出一个异常)
2.后置通知
在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
3.异常通知
在方法抛出异常退出执行的通知
4.最终通知
在目标方法成功执行之后调用通知。某连接点退出的时候执行的通知(不论是正常返回还是异常退
出)
5.环绕通知
通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

springBean

声明Bean的注解:

@Component :组件,没有明确的角色
@Service :在业务逻辑层(service层)使用
@Repository :在数据访问层(dao层)使用.
@Controller :在展现层(MVC–SpringMVC)使用

注入Bean的注解:

@Aautowired : Spring提供的注解.
@Inject : JSR-330提供的注解
@Resource : JSR-250提供的注解

SpringMVC常用注解:

@Controller :注解在类上声明这个类是springmvc里的Controller,将其声明为一个spring的Bean.
@RequestMapping :可以注解在类上和方法上映射WEB请求(访问路径和参数)·
@RequestMapping(value= “/convert”,produces+{“application/x-wisely”})设置访问URL 返回值类型
@ResponseBody :支持将返回值放入response体内而不是返回一个页面(返回的是一个组数据)
@RequestBody :允许request的参数在request体中,而不是直接连接在地址后面次注解放置在参数前
@Path Variable :用来接收路径参数如/test/001,001为参数,次注解放置在参数前
@RestController : @Controller + @ResponseBody组合注解
@ControllerAdvice :通过@ControllerAdvice

spring事务管理

编程式事务在项目中很少使用,这种方式需要注入一个事务管理对象TransactionTemplate,然后在我们代码中需要提交事务或回滚事务时自己写代码实现。(我们在代码中要手动的进行事务提交,还需在代码添加操作)

声明式事务管理建立在AOP基础上,本质是对方法前后进行拦截,所以声明式事务是方法级别的。(只要声明那个方法需要在事务中执行,那么spring就会为方法添加事务功能。出现异常自动回滚,没有异常提交事务)

Spring 定义了七种传播行为:

  1. PROPAGATION_REQUIRED
    指定的方法必须在事务内执行,若当前存在事务,加入到当前事务中,若当前没有事务,则创建一个新事务,这种传播行为是最常见的,也是spring 默认的传播行为

A事务方法 调用B事务方法,B的事务会合并到A事务中,若B事务出现异常,A事务也会回滚

A方法(没有事务)调用B事务方法,那么B方法会开启自己的事务,在事务中执行

  1. PROPAGATION_SUPPORTS
    支持当前事务,如果当前没有事务,就以非事务方式执行。

A事务方法 调用B方法,那么B方法就会合并到A事务中,若B事务出现异常,A事务也会回滚

A方法(没有事务)调用B方法,那么B方法就不在spring管理的事务中执行(在JdbcTemplate事务执行)

  1. PROPAGATION_REQUIRES_NEW
    总是新建一个事务,如果当前存在事务,把当前事务挂起,直到新建的事务结束

A事务方法 调用B方法,那么B方法会单独开启一个事务执行,A出现异常不影响B方法的事务

A方法(没有事务)调用B方法,那么B还会单独的开启一个事务,A方法的异常不影响B事务

  1. propagation_mandatory
    当前存在事务,就加入该事务。不存在,抛出异常
  2. propagation_not_supported
    以非事务方式执行,如果当前存在事务,就把当前事务挂起
  3. propagation_never
    以非事务方式进行,如果当前存在事务,就抛出异常
  4. propagation_nested
    当前存在事务,则在嵌套事务内执行。不存在,则按required属性执行

声明式事务不生效的场景

  1. @Transactional 应用在非 public 修饰的方法上
  2. @Transactional 注解属性 propagation 设置错误
  3. 同一个类中方法调用,导致@Transactional 失效
  4. 异常被 catch 捕获导致@Transactional 失效
  5. 数据库引擎不支持事

BeanFactory和ApplicationContext

BeanFactory 和ApplicationContext都是spring框架中定义的接口。

spring要生成并管理对象,底层使用的是工厂模式

在spring容器中,BeanFactory 接口是Ispring框架中要实现的最基础的接口,定义了管理 bean的最基本的方法,例如获取实例、基本的判断等

BeanFactory 有多个子接口来进一步扩展 bean 相关的功能。

ApplicationContext 也间接继承了 BeanFactory ,它们都可以当做Spring的容器,Spring容器是生成Bean 实例的工厂,并管理容器中的Bean。

区别:

​ 1.BeanFactory 是最顶层的接口,里面只是基础功能定义。 ApplicationContext 继承了BeanFactory,并扩展了功能。

​ 2.BeanFactory 是 Spring 框架的基础设施,面向Spring本身;而ApplicationContext 面向使用Spring的开发者,相比 BeanFactory 提供了更多面向实际应用的功能,几乎所有场合都可以直接使用Application。

​ 3.使用ApplicationContext实现,在spring启动时,创建单例bean;使用BeanFactory 实现,在spring启动时,不会创建单例bean,而是第一次getBean() 时创建。

springBean的生命周期

什么是Bean?

​ 严格上讲,Bean是指Spring 框架创建出来的对象。spring框架创建出来的对象与我们自己new 的对象 是不同的。

宏观来讲,SpringBean 的生命周期可以分为 5 个阶段(触发创建bean的整个过程):

1.实例化 Instantiation

​ 就是new,创建一个原始对象

2.属性赋值 Populate

​ 给属性注入值

3.初始化 Initialization

​ 初始化bean,根据我们的配置,为bean 添加额外的功能。

3.1 如果Bean实现 BeanNameAware 执行 setBeanName
3.2 如果Bean实现 BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象setApplicationContext 对象。
初始化
3.3 如果存在类实现 BeanPostProcessor(AOP), 执行 postProcessBeforeInitialization
3.4 如果Bean实现 InitializingBean 执行afterPropertiesSet
如果配置了自己的初始化方法,也可以调用自己的 <bean id="" class="" init-method="init">
3.5 如过存在类实现 BeanPostProcessor(AOP), 执行postProcessAfterInitialization

4.将 bean 对象放入到容器中,使用

​ 完整的bean创建好后,将 bean 对象放入到容器中,可以使用。

5.销毁 Destruction

​ 如果Bean不再被使用,通过一些方法销毁。

如果 Bean 实现 DisposableBean 执行 destory 
如果配置了自己的销毁方法 <bean destoty-method="customerDestroy"> 指定销毁方法 customerDestory

Spring支持如下5种作用域:

  • singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
  • prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
  • request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
  • session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
  • globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

作用域–scopy

singleton单例(默认) : bean在每个Spring ioc 容器中只有一个实例。

prototype多例:一个bean的定义可以有多个实例。

request:每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效。

session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring

ApplicationContext情形下有效。

global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

Spring中的Bean(单例)是线程安全的吗?

不是线程安全的

Spring 容器中的 Bean 是否线程安全,容器本身并没有提供 Bean 的线程安全策略,因此可以说Spring 容器中的 Bean 本身不具备线程安全的特性,但是具体还要结合具体 scope(作用域)的 Bean 情况。

原型Bean(prototype)

​ 每次创建一个新对象。创建多个对象,每个对象中都包含一份成员变量。也就是线程之间并不存在 Bean 共享,自然是不会有线程安全的问题。

单例Bean(singleton)

​ 所有线程共享一个单例Bean对象,因此存在资源的竞争。

​ 如果单例Bean 是一个无状态的Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那这个单例Bean是线程安全的。比如 Spring MVC 的Controller、Service、Dao等,这些Bean 大多是无状态的,只关注于方法本身。

​ 如果Bean 有状态,数据共享,对数据的操作可能会导致B数据发生变化,那么就是不安全的,就需要开发人员自己来进行线程安全的保证,最简单的就是改成原型Bean。

解决方法:

​ 使用ThreadLocal存储变量,每个线程中都会复制一份成员变量(副本变量),线程独自使用。

Spring 的 Bean 作用域(scope)类型

​ 1.singleton:单例,默认作用域,在spring中只存在一个 bean 实例,即只创建一个对象。

​ 2.prototype:原型,每次创建一个新对象。

Bean循环依赖

Java 中循环依赖的场景有:

​ 1.构造器的循环依赖。构造器的循环依赖问题无法解决,只能抛出异常。

​ 2.field 属性的循环依赖。就是A对象依赖了B对象,B对象依赖了A对象。

// A依赖了B
class A {
    B b; // B b = null;
}

// B依赖了A
class B {
    A a; // A a = null;
}

A a = new A();
B b = new B();
a.b = b;
b.a = a;

如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。

但是在Spring中循环循环依赖就是一个问题了,为什么?

因为,在spring中,一个对象并不是简单 new 出来了,而是会经过一系列的Bean 的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。(创建原始对象,属性注入值(注入时默认值不能为空。))当然,在spring中,出现循环依赖的场景很多,有的场景spring 自动帮我们解决了,而有的场景则需要程序员来解决。

产生循环依赖的问题,主要是:A创建时–>需要B --> B去创建 --> 需要A,从而产生了循环。

解决:Spring 内部有三级缓存

提供了3个级别的缓存,来存储不同阶段的对象。

​ singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的 Bean实例。

​ earlySingletonObjects 二级缓存,用于保存实例化完成的Bean实例。

​ singletonFactories 三级缓存,用于保存bean 创建工厂,以便于后面扩展有机会创建代理对象。

过程:

​ A,B循环依赖,先初始化A,此时先初始化一个半成品A,并放入缓存中,再初始化依赖的B,初始化B时发现B依赖A,也就是循环依赖,就从缓存中找半成品A并注入,之后初始化完毕 B,再回到 A 的初始化过程就解决了循环依赖。这里需要一个Map来缓存半成品A,即二级缓存。但这个二级缓存存的是Bean对象,如果这个对象存在代理,那应该是注入的是代理,而不是 Bean,此时二级缓存无法即缓存bean,又缓存代理,因此三级缓存做到了缓存工厂,也就是生成代理(AOP)。

小结:

​ 二级缓存能解决循环依赖,三级缓存解决的是代理。

Spring MVC 运行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jV7kVam-1639636433493)(C:\Users\XiaoEn\AppData\Roaming\Typora\typora-user-images\1634472995258.png)]

1.浏览器发起请求

​ 地址(login/toLogin)

​ 被前端请求分发器(DispatcherServlet)拦截

2.DispatcherServlet调用HandleMapping(映射处理器)找到处理器(控制器,即我们自己所写的Controller)将解析的结果返回DispatcherServlet

3.DispatcherServlet 调用对应的控制器,在到达控制器之前,会先进入HandlerAdaPter(处理适配器) 参数的封装,数据类型的转换

4.最终到我们自己写的控制器 接收数据 处理 返回ModelAndView(包含视图名 数据) 返回给DispatcherServlet

5.DispatcherSerclet将结果交给视图解析器(InternalResourceViewResolver)找到对应的.jsp文件

6.把Model (数据)交给View (jsp)

7.由jsp做出最终响应

Spring MVC的常用注解解释

@Controller 声明Action组件
@Service 声明Service组件 @Service(“myMovieLister”)
@Repository 声明Dao组件
@Component 泛指组件, 当不好归类时.
@RequestMapping("/menu") 请求映射
@Resource 用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name=“beanName”)
@Autowired 用于注入,(srping提供的) 默认按类型装配
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody
@Scope(“prototype”) 设定bean的作用域

@Controller注解的作用

在Spring MVC 中,控制器Controller 负责处理DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在
Spring MVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等
HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。@Controller 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。

@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是Spring MVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
在Spring MVC 的配置文件中定义MyController 的bean 对象。
在Spring MVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。

@RequestMapping注解的作用

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明(下面有相应示例)。
value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
method: 指定请求的method类型, GET、POST、PUT、DELETE等; consumes,produces
consumes: 指定处理请求的提交内容类型(Content-Type),例如 application/json,
text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返
回;
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

@ResponseBody注解的作用

作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指
定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使
用;
@PathVariable和@RequestParam的区别
请求路径上有个id的变量值,可以通过@PathVariable来获取@RequestMapping(value =
“/page/{id}”, method =
RequestMethod.GET)
@RequestParam用来获得静态的URL请求入参 spring注解时action里用到。

Servlet的过滤器与Spring拦截器详解

实现原理不同

过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的。

使用范围不同

我们看到过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。

触发时机不同

过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

拦截的请求范围不同

过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。

SpringBoot知识点

Spring Boot概述

Spring Boot是由Pivotal团队提供的在Spring框架基础上开发的框架,其设计<u>目的是用来简化应用的初始搭建以及开发过程。</u>

​ Spring Boot本身幷不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。

 Spring Boot以**约定大于配置**的核心思想,从而使开发人员不再需要定义样板化的配置。它集成了大量常用的第三方库配置(如Redis(非关系型数据库,做缓存用 ),MongoDB,Jpa RabbitMQ(消息队列),Quartz(定时组件)等等), Spring Boot应用中这些第三方库几乎可以零配置的开箱即用,通过这种方式, Spring Boot致力于在蓬勃发展的快速应用开发领域成为领导者。

​ spring官网:spring.io

​ Spring Boot你只需要“run"就可以非常轻易的构建独立的、生产级别(公司里面商业级别的)的Spring应用。大部分Spring Boot应用只需要很少的配置。(必须要配的:数据库连接、扫描Mapper.xml所在的包)

Spring Boot特点(官网)

​ 创建独立的spring应用程序

​ 直接内嵌tomcat、jetty和undetow

​ 提供了固定化的“starter”配置,以简化构建配置

​ 尽可能的自动配置,如:安全指标、运行状况监测和外部化配置等

​ 绝对不会生成代码,并且不需要XML配置

Spring Boot的核心功能

起步依赖

​ 起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

自动配置

​ Spring Boot的自动配置士一个运行时(更准确的说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

spring Boot 自动配置

springboot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories 配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以***AutoConfiguration结尾类命名的,他实际是javaConfig形式的spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server port,而xxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

spring实现自动装配的核心仍然是使用注解标签。

@SpringBootApplication是springboot的核心注解,其中包含@SpringBootConfiguration,@EnableAutoConfiguration,@ComponmentScan

@ComponmentScan :对启动类所在类的包中的类扫描,它默认扫描的是与该类同级的类或者同级包下的所有类。

@SpringBootConfiguration:通过源码得知它是一个@Configuration,相当于之前的配置文件功能。扫描带有@Configuration注解标签的类(等同于之前的xml文件)

@EnableAutoConfiguration:自动装配的注解标签 最重要的,根据我们的配置,去加载一些第三方组件.是这里最重要的注解,它实现了对Spring Boot应用自动装配的功能。它的配置数据在 META-INF/spring.factories 中,我们打开 spring-boot-autoconfigure jar 中 的该文件,发现对应着许多个 XXXAutoConfiguration 配置类。

@Import({AutoConfigurationImportSelector.class})  加载选择器在 spring-boot-autoconfigure-2.4.7.jar /META-INF /spring.factories 文件中,结合pom.xml文件中所添加的依赖进行自动装配

@Configuration :加入@Configuration注解,表明这就是一个配置类。有一个 myBean()的方法 ,并用@Bean 进行注释,返回一个 MyBean()的实例,表明这个方法是需要被 Spring 进行管理的 bean。@Bean 如果不指定名称的话,默认使用 myBean 名称,也就是小写的名称。

@Bean:相当于 XML 中的,放在方法的上面,而不是类,意思是产生一 个 bean,并交给 spring 管理。

4.Spring Boot 集成JDBC(主要 事务管理)

数据源配置:在我们访问数据库的时候,需要先配置一个数据源,下面分别介绍一个几种不同的数据库配置方式。

​ 首先,为了连接数据库需要引入jdbc支持,在pom.xml中引入如下配置:

<dependency> 
	<groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>

​ 在application.yml中配置数据源信息

#spring配置
spring:
#数据库连接配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/ssm_db?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

​ 使用JdbcTemplate操作数据库

​ Spring的JdbcTemplate是自动配置的,你可以直接使用@Autowired来注入到你自己的bean中来使用。

Spring Boot 整合阿里数据源(数据连接池的支撑)

导入阿里数据源jar

<dependency> 
	<groupId>com.alibaba</groupId> 
	<artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>

在 yml 文件中注册阿里数据库连接池

#spring配置
spring:
#数据库连接配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/ssm_db?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    filters: stat
    initialSize: 5 #初始化时建立物理连接的个数
    maxActive: 20 #最大连接池数量

5.Spring Boot 集成 mybatis

<dependency>
	<groupId>org.mybatis.spring.boot</groupId> 
	<artifactId>mybatis-spring-boot-starter</artifactId> 
	<version>2.1.4</version>
</dependency>

在 application.yml 中配置数据源信息

mybatis:
  type-aliases-package: com.ff.back.bean
  mapper-locations: classpath:mapper/*Mapper.xml
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: true

推荐一款插件:MyBatisX。

最后,在SpringBoot中的启动类上配置@MapperScan(“com.ff.back.mapper”),去扫描放接口的包,然后在接口层配置@Repository。

补充:配置日志打印
logging:
  level:
    com.ff.back.mapper: trace #持久层的日志打印 trace 日志级别
  file:
    name: D:\\logs\\log.log

6.SpringBoot后端各层需要配置的注解

启动类:

@SpringBootApplication
@MapperScan("com.ff.back.mapper")

bean层/pojo层:

@Component
@TableName(value = "user")

config层:

@Configuration

controller层:

@RestController
@RequestMapping(path = "/api/login")

dao层/mapper层(持久层):

@Repository

service层:

@Transactional
@Service
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值