框架源码知识点(spring)二

Spring AOP知识点

AOP面向切面编程,处理的对象是切面,在处理日志,安全管理,事务管理等方面有非常重要的作用。用来在程序运行期间对IOC做补充

AOP(spring aop)底层用的是代理(动态代理)

Spring AOP and AspectJ AOP 有什么区别?AOP 有 哪些实现 方式?
AOP 实现的关键在于代理模式 ,AOP 代理主要分为静态代理和动态代理。静 态 代理的代表为 AspectJ ;动态代理则以 Spring AOP 为代表。
( 1) AspectJ 是静态代理的增强 ,所谓静态代理 ,就是 AOP 框架会在编 译阶段 生成 AOP 代理类 ,因此也称为编译时增强 ,他会在编译阶段将 AspectJ(切面)织 入到 Java 字节码中 ,运行的时候就是增强之后的 AOP 对 象。
( 2) Spring AOP 使用的动态代理 ,每次运行时在内存中临时为方法生成一个 AOP 对象 , 这个AOP 对象包含了目标对象的全部方法 ,并且在特定的切点做了增强处 理 ,并回调原对象的方法。

代理分为:1.静态代理,需要自己创建代理类,不好的地方是需要为每一个被代理的类创建代理类,这种实现方式成本高 2.动态代理,其中又分为jdk动态代理(必须保证被代理的类实现了接口)和cglib动态代理(不需要接口)

jdk动态代理是基于反射机制,生成一个实现代理接口的匿名类。cglib是基于继承机制(字节码增强),继承被代理类,生成一个子类,然后覆盖其中的方法。所以性能上会有差异。cglib底层是基于asm第三方框架,对代理对象类的class文件加载进来,通过修改字节码生成子类来处理(字节码增强)

jdk动态代理只能针对实现了接口的类,不能对没有实现接口的类进行代理。cglib动态代理因为是基于继承机制,所以该类或方法最好不用声明为final.

在老版本中,cglib的速度是jdk速度的10倍左右,但是在新版本中,1w次执行下,jdk7及8的动态代理性能比cglib要好20%左右

JDK动态代理和CGLIB动态代理都是在运行时动态地创建代理对象

aop中,被注入到ioc容器的是动态代理对象,而不是被代理的对象

cglib会使用到Enhancer相关字节码增强类

Spring AOP底层原理

spring aop的代理通过ProxyFactory进行封装。封装了代理和@Before @After等相关逻辑。ProxyFactory会判断类是否实现了接口,如果实现了接口则使用jdk动态代理,如果没有则使用cglib动态代理。具体逻辑是在DefaultAopProxyFactory实现,不同版本spring,其实现逻辑不一样。整个spring aop的底层就是ProxyFactory。

spring aop设置的切面规则和切面的逻辑是通过beanPostProcessor来作用到相关的bean的,其具体beanPostProcessor是AnnotationAwareAspectJAutoProxyCreator,@Import(AnnotationAwareAspectJAutoProxyCreator.class)和@EnableAspectJAutoProxy效果一样,AnnotationAwareAspectJAutoProxyCreator是个BeanPostProcessor。每个bean在初始化后会判断是否需要AOP。

执行被代理的对象的方法是通过反射来实现的

@Lazy也用到了spring动态代理 ProxyFactory

Advisor=Advise(代理逻辑)+PointCut(切面规则)
Advice + Target Object = Proxy
将 Advice 应用于目标对象后创建的对象称为代理。

TargetSouce表示被代理对象,这个对象可以灵活改变

连接点和切点的区别:
Spring Aop中四个重要概念,切点,切面,连接点,通知
通知: 就是我们编写的希望Aop时执行的那个方法。我们通过Aop希望我们编写的方法在目标方法执行前执行,或者执行后执行。
切点:切点就是我们配置的满足我们条件的目标方法。比如我们规定:名字前面是select开头的才执行我们自定义的通知方法。那么这些select开头的方法就是切点。
连接点:连接点可以说是切点的全集。切点是连接点的子集。也可以理解为,连接点是我们没有定义那个select开头规则时,满足条件的全部的方法。
切面:切面是切点和通知的组合称谓,就是变相给组合起了个名

Spring 事务知识点

什么是事务?事务是一种机制。把一组业务当成是一个业务来做,要么成功要么都失败,保证业务操作完整性。

声明式事务4大特性 ACID 原子性(一组业务要么都成功,要么都失败)、一致性(事务前后要保证数据的一致性)、隔离性(在并发情况事务之前要相互隔离)、持久性(数据一旦保存就是持久的)

事务分为编程式事务:在代码中直接加入处理事务的逻辑,显示调用beginTransaction、commit、rollback , 声明式事务:在方法外部通过注解或配置文件定义事务。声明式事务可以通过AOP来实现。

不管什么事务底层都是控制connection

事务配置的属性包含:isolation设置事务的隔离级别、propagation事务传播行为,哪些事务可回滚、是否只读、超时时长等

事务的使用需要用到事务管理器TransactionManager,无论是编程式还是声明式,我们可以直接使用事务管理器来管理事务,而无需了解其底层是如何实现的。

Spring 事务原理

切面编程和事务都需要用到AOP,它们的原理都是通过beanPostProcessor实现的。只不过切面编程用到的是AspectJAwareAdvisorAutoProxyCreator这个beanPostProcessor,而事务用的是InfrastructureAdvisorAutoProxyCreator,它们父类都是AbstractAdvisorAutoProxyCreator。AspectJAwareAdvisorAutoProxyCreator会去解析aspectj定义的切面及其规则,而因为事务不需要解析切面,所以用的不是AspectJAwareAdvisorAutoProxyCreator,只需去解析添加advisor即可。

Advisor=Advise(代理逻辑)+PointCut(切面规则)

事务AOP时添加的advisor的advice就是事务拦截器

事务流程原理,会用到threadLocal,事务会将创建的connection存放到threadLocal中。这样被代理对象就可以拿到当前线程的connection。不同的事务用的是不同的connection,新开启事务会创建新的connection。但是在同一个事务中嵌套另外一个事务时,是否用同一个connection,要看事务传播配置。

为了处理在嵌套事务的时候出现threadLocal connection被覆盖,会有挂起操作。挂起操作逻辑在TransactionSynchronizationManager中进行存储实现。

TransactionAttributeSource用于缓存@Transactional注解的配置
TransactionAttribute用于存放每个属性值

开启事务及相关处理逻辑在DataSourceTransactionManager这个类里。会依次进行新建conn,设置隔离级别,设置只读,设置autoCommit,定义超时时间等操作。这一系列操作形成了一个事务。所以说事务不是一个新的操作术语,事务其实就是上面的几个步骤的集合一起实现了事务这个概念。

事务传播行为总共有7种,具体看Propagation这个枚举。不开启新的事务是指不会开启新的数据库连接conn。其中NOT_SUPPORTED表示不支持事务,不会用spring的事务,即不会使用spring创建的连接。而是用jdbcTemplate自己的事务,自己创建的连接conn。注意事务上面的概念。

Spring MVC知识点

springmvc和spring都会扫描bean,springmvc会扫描controller,而spring会扫描除了controller外的bean

Spring mvc基于Servlet API上构建。是Spring框架的一部分,基于java实现的一个轻量级web框架。spring mvc围绕着前端控制器模式设计,核心是DispatchServlet。

springmvc需要用到spring-web、spring-webmvc。导入spring-webmvc后会自动导入spring-web ioc等。

DispatcherServlet又叫前端控制器,核心调度器,分发器

web.xml初始化参数的contextConfigLocation也可以不配置:springmvc会自动去WEB-INF去找一个名字叫做{servlet-name}-servlet.xml

servlet-mapping的映射规则url pattern表示的含义
/ 除了.jsp的请求都会被匹配
/*所有的请求都会被匹配
.do、.action url结尾以.do或者.action的请求会匹配

DispatchServlet拦截处理请求流程:
1.客户端发送请求,由tomcat接收到对应请求。
2.springmvc的前端控制器DispatchServlet接收到对应的请求并进行拦截。
3.DispatchServlet根据请求url调用HandlerMapping,匹配返回给DispatchServlet对应的Handler(具体的处理请求方法)
4.DispatchServlet调用HandlerAdapter(负责调用Handler,并返回ModelAndView或json什么的),由HandlerAdapter执行Handler,Handler会封装视图和模型为ModelAndView返回给HandlerAdapter。
5.HandlerAdapter将ModelAndView(此时View视图对象中还没有包含jsp)返回给DispatchServlet。
6.DispatchServlet调用视图解析器ViewResolver(根据ModelAndView的视图名找具体的jsp封装在View视图对象中),解析ModelAndView(此时View中已经包含了jsp),并返回View视图对象给DispatchServlet。
7.DispatchServlet调用View视图对象的渲染方法进行渲染(将jsp转换成html),并将渲染结果返回给DispatchServlet。
8.DispatchServlet将渲染结果返回给客户端。

400是springmvc自定义的错误码 不是http错误码

分布式一般做前后端分离 ssm一般不会做前后端分离

rest是客户端映射到服务器资源的一种架构设计,是一种优雅的url风格,restful主要是规范化url设计

request.method只支持GET/POST/HEAD,要支持PUT和DELETE,需要做些调整

DispatcherServlet url-pattern设置为/后,.css .html等都会被DispatcherServlet拦截,所以为了能够访问.css .html,需要进行访问静态资源相关配置。<mvc:resources mapping=“” location=“”>,也可以配置mvc:default-servlet-handler。
配置了mvc:default-servlet-handler后,当请求没有映射到一个servelt时,会调用tomcat默认servlet,这个servlet会处理静态资源访问。
这个tomcat默认servlet不是DispatcherServlet,DispatcherServlet是springmvc的默认处理servlet,而不是tomcat默认servlet。

modelAndview 即包含model和view ,然后交给viewReslover解析器解析。默认解析器只支持解析jsp

ModelAndView传输数据和视图,底层都是将数据设置到request

读写session方式有
1.通过servlet api 其中又包含参数绑定的方式和自动注入的方式(推荐用第二个-自动注入)
在这里插入图片描述
在这里插入图片描述
2.通过Session相关注解
在这里插入图片描述
3.通过@ModelAttribute的方式(不推荐,存在线程安全问题)
在这里插入图片描述
以上3种方式的获取servlet­­api的线程安全问题:

  1. 通过参数绑定的方式
    是线程安全的,因为参数绑定变量时方法级别,所以每次请求方法都会创建一个新的私
    有变量。
    2.通过自动注入的方式@AutoWired
    是线程安全的,spring底层通过自动注入 将 servlet api相关bean对象 封装到ThreadLocal(是绑定
    在线程上面的)里面.
    3.通过@ModelAttribute的方式
    不是线程安全的,控制器是单例的,并且变量声明在类的级别中(共享变量)。
    所以一般使用局部变量,或使用ThreadLocal

关于@Autowired注入获取servlet api线程安全问题,讲到会用到ThreadLocal。这里只是在spring-web这个spring子项目中会将servlet api相关bean对象如HttpServletRequest,HttpServletResponse,Session存放到ThreadLocal中。spring其它bean是不会放到ThreadLocal中的。

拦截器
采用aop思想,类似servlet过滤器。用来拦截方法,在方法执行前后处理一些跟主业务逻辑无关的逻辑。比如实现权限控制、日志、异常记录、记录方法执行事件等。
拦截器是springmvc的,过滤器是servlet的。过滤器先执行。
拦截器跟过滤器区别:
1.执行顺序有区别
请求->tomcat->过滤器->Servlet(DispatchServlet)->拦截器->Controller
2. 过滤器基于函数回调,拦截器基于java反射(因为aop)
3.过滤器依赖于servlet容器(tomcat),而拦截器依赖于springmvc
4.过滤器几乎对所有请求都可以起作用,而拦截器只能对springmvc请求起作用。
5.拦截器可以访问方法的上下文,而过滤器不行。

前后端分离项目中,字符串国际化可以交由前端做,但是接口返回数据国际化还是得交给后端来做
比如数据验证错误信息和代码字符串国际化

Spring MVC原理

springmvc原理其实就是:springmvc父子容器启动流程和springmvc请求流程两个部分。

springmvc请求流程
springmvc只是spring的一个模块,它不是一个新的框架
servlet是一个单例,不会每次请求都创建
HandlerMapping可以配置,不配置的话用默认的,而且可以配置多个,可以配置优先级
在这里插入图片描述HandlerAdapter种类主要有4种,每种handlerMapping都有一种apdater和它对应。
1.HttpRequestHandlerAdapter:适用于实现HttpRequestHandler接口的处理器
2.SimpleServletHandlerAdapter:用于继承HttpServlet的处理器
3.SimpleControllerHandlerAdapter:适用于实现Controller接口的处理器
4.RequestMappingHandlerAdapter:适用于开启注解的处理器(一般使用这种)

springmvc请求流程图在这里插入图片描述
在这里插入图片描述
RequestMappingInfo封装了RequestMapping注解信息,封装成一个个Condition,这些condition用来作匹配用的
在这里插入图片描述解析地址的时候,会以key=path/name,value=HandlerMapping放到pathLookup或nameLookup等Map中。
在这里插入图片描述

解析json的Converter
在这里插入图片描述

springmvc父子容器启动流程
(spring为父容器、springmvc为子容器)
DispatcherServlet也需要加载一个spring容器

为什么要弄两个ioc容器?一个不可以吗
因为spring mvc 是个前端框架,不一定只用于和spring 整合(即 Spring MVC 可以单独用作一个 Web 应用的前端控制器,而不需要使用 Spring 的其他部分(例如 Spring Core 或 Spring Data)),因此是很有必要设计一个自己管辖的ioc容器,有点单一职责的味道。

启动流程图
图。

总结

  1. spring 启动会立即初始化ioc容器 为父容器。
  2. spring mvc 在发起第一次请求时会初始化 spring mvc容器 为子容器。
  3. spring 容器初始化的范围是除了controller层的,比如dao层 service层。
  4. spring mvc 初始化的范围是controller层。
  5. 子容器能访问父容器中的对象,父容器访问不到子容器中的对象。
  6. 在controller层查找容器中的对象会先查找子容器再查找父容器,其他层都是直接从父容器中查找
  7. 父容器和子容器中不能存在相同的bean。
    Root WebApplicationContext为父容器(spring ioc) createRootApplicationContext(),Servlet WebApplicationContext(spring mvc ioc) createServletApplicationContext()

SPI(Service Provider Interface,服务提供者接口,为tomcat提供的机制):
其实就是根据Servlet厂商(服务提供商)提供要求的一个接口, 在固定的目录(META-INF/services)放上以接口全类名 为命名的文件, 文件中放入接口的实现的全类名,该类由我们自己实现,按照这种约定的方式(即SPI规范),服务提供商会
调用文件中实现类的方法, 从而完成扩展。
在这里插入图片描述Tomcat为服务提供者。
实现类为SpringServletContainerInitializer.class

SpringServletContainerInitializer实现逻辑如下:即Tomcat启动的时候会把遍历实现了WebApplicationInitializer接口的类,并执行onStartup方法。
g-blog.csdnimg.cn/direct/6d5376f4c29d48e0b0a07ecbf7fa9cb8.png)Servlet ioc容器就是根据spi规范(机制)来进行启动的。在启动的时候,xml和注解方式(springboot)启动的实现会有不同。

springmvc父子容器启动原理是根据SPI规范来实现的。
在这里插入图片描述
1.先通过spi机制,找到spi实现类SpringServletContainerInitializer.class。
2.SpringServletContainerInitializer.class会找到所有实现WebApplicationInitializer接口的类,包含了父子容器的WebApplicationInitializer接口实现类,并执行其onStartup方法。
3.onStartup中会创建父子容器
4.初始化父子容器(初始化ContextLoaderListener、初始化DispatcherServlet)及其他操作,如加载、初始化bean之类。

spring子容器在加载bean前会注册一个ContextRefreshListener监听器,当该子容器在加载完所有bean后会发送ContextRefreshListener的事件,调用onApplicationEvent方法,然后通知FrameworkServlet进行onRefresh方法,在这个方法中会进行子容器初始化操作。比如初始化handlerMapping viewResolvers等,为后续SpringMVC处理请求做准备。如果解析到没有配置handlerMapping viewResolvers等,则会根据情况使用默认的HandlerMapping,ViewResolvers等。

是否可以把所有Bean都通过Spring容器来管理?(Spring的applicationContext.xml中配置全局扫描)
不可以,这样会导致我们请求接口的时候产生404。 如果所有的Bean都交给父容器,SpringMVC在初始化HandlerMethods的时候(initHandlerMethods)无法根据Controller的handler方法注册HandlerMethod,并没有去查找父容器的bean;
也就无法根据请求URI 获取到 HandlerMethod来进行匹配。
因为springmvc在代码中是这么写的:不会去父容器找controller,只会在子容器中找。

SpringData&JPA

为什么要用SpringData 统一了持久层 提升了开发效率 针对不同的存储方式提供了不同的模板对象来进行数据存储

springdata包含多个子项目,比如springdata jdbc、springdata mongodb、springdata redis、springdata jpa…针对不同数据库存储的实现。

JPA(这是一种规范,而非上面讲的springdata jpa)是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系ORM(对象关系映射),并将运行期的实体对象持久化到数据库中。

spring data jpa针对关系型数据库实现

springdata jdbc支持mybatis查询,springdata jpa默认使用hibernate实现

jpa和jdbc的相同点:1.都跟数据库操作有关,jpa基于jdbc,是jdbc的升级版 2.jdbc和jpa都是一组规范接口 3.都是由sun官方推出。不同点:1.jdbc是由各个关系型数据库实现,jpa是由全自动ORM框架实现 2.jpa需要依赖jdbc

Java Database Connectivity,简称JDBC

hibernate无需自己创建表

jpa支持对象和原生sql操作

JPA对象的分4种状态:临时状态、持久状态、删除状态、游离状态。JPA在对持久状态进行更新,就算不调用更新方法,直接提交事务也会进行更新数据库。如果对一个游离态的对象进行操作(比如删除)会报错,需要将游离态变为持久态后才能操作。

springdata jpa是spring提供的一套简化JPA开发的框架。可以在只写dao层接口而无需写实现的情况下对数据库进行访问和操作,同时提供了crud之外的比如分页、排序、复杂查询等操作。springdata jpa基于jdk动态代理封装了jpa。

spring jpa的定位是为简单数据库操作,简单业务逻辑而产生的。复杂用mybatis

springdata jpa没有多表关联操作的文档,它只是整合hibernate,实现用的是hibernate,要看相关文档就去hibernate官方文档查看

spring jpa Repository原理:动态代理+jpa实现。jdkDynamicAopProxy AOP统一处理类,调用jpa的Repository统一实现,调用jpa api

java web三大组件

Servlet
tomcat是一个servlet容器,里面运行了很多个servlet实例
servlet是一个接口,只要实现了servlet,就可以处理请求。一个项目可以包含多个servlet。

/index.jsp加了/之后表示根目录下的index.jsp。
重定向是在客户端发生的,客户端会认为根目录=8080/
转发是在服务端,服务端会认为根目录=8080/springmvc-servlet
所以重定向的话 /index.jsp实际访问的地址是8080/index.jsp,这是会报错的,需要将/去掉

请求和转发是一次请求,重定向是 两次请求。重定向也是一种资源跳转方式。重定向加/的时候一定要写资源访问路径。

重定向地址栏会发生变化,可以访问其它站点服务器的资源,由于重定向是两次请求,不能使用request对象来共享数据。所以当两个Servlet需要传递数据的时候,选择forward转发。不建议使用sendRedirect进行传递。

cookie有效期 默认关闭浏览器就失效 ,但是可以设置有效期。session也是一样,浏览器关闭或session超时或手动销毁就失效。
Cookie 存储在客户端,即用户的浏览器中。
Session 数据存储在服务器端。通常,服务器为每个会话生成一个唯一的 Session ID,并将该 ID 通过 Cookie 或 URL 参数传给客户端。

servlet执行原理
1.当服务器接收到客户端浏览器的请求后,会解析请求的URL路径,获取访问的Servlet的资源路径。
2.查找web.xml文件,查看是否有对应的资源(即接收请求的Serlvet)。
3.如果有,则找到对应的全类名。
4.tomcat会将对应Servlet字节码加载进内存,并且创建其对象。(如果配置了在Server启动时就加载Servlet,则该步骤会提前,详细看servlet生命周期)
5.调用其方法进行处理。

servlet生命周期
Servlet的生命周期可以被归纳为以下几步:
1.装载Servlet,这一项操作一般是动态执行的。但是,Servlet通常会提供一个可配置的选项,用于在Server启动时强制装载和初始化特定的Servlet(就是load-on-startup这个配置,可以把Servlet的创建提前到服务器启动时)。
2.Server创建一个Servlet实例。
3.Server调用Servlet的init方法。
4.一个客户端请求到达到达Server。(如果没有设置在Server启动时就加载创建Servlet实例,则这一部应该先执行,然后才装载Servlet操作。即先等客户端请求到了之后才开始装载Servlet)
5.Server创建一个请求对象。
6.Server创建一个响应对象。
7.Server调用Servlet的service方法,并传递请求和响应对象作为参数。
8.service方法获得请求对象的信息,处理请求,访问其它资源,获得需要的信息。
9.service方法使用响应对象的方法,将响应传回server。最终到达客户端。
10.对于一个servlet有多次客户端请求,则init方法只执行一次,下次直接调用service方法。
11.当server不在需要servlet,比如server关闭的时候。server调用Servlet的destroy方法。
总的来说,Servlet生命周期分为:实例化,初始化,提供服务,销毁。

servlet是一个单例,不会每次请求都创建
不是每次相同请求/url/方法进来,都会创建一个Servlet

servlet配置方式
servlet2.5之前在web.xml配置,3.0开始用注解方式@WebServlet(“/hello”)

servlet线程安全
如何保证线程安全?尽可能使用局部变量。

ServletContext上下文:作用范围是tomcat服务器启动和关闭。
作用范围包括:
一次请求范围
一次会话范围:浏览器打开和关闭,比如session,cookie
一次应用范围:tomcat服务器启动和关闭 ,比如ServletContext上下文

ServletContext是一个全局对象,对应一个Tomcat中的web应用

Filter过滤器
过滤器是出于客户端和服务器目标资源之间的一道过滤技术。可以将请求拦截下来,完成一些特殊的功能。
过滤器生命周期方法
1.init在服务器启动后,会创建Filter对象,然后调用init方法。方法只执行一次,用于加载资源
2.doFilter每一次请求被拦截时会执行,可以执行多次
3.destroy在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭的,则会执行destroy方法,该方法只执行一次,用于释放资源。
可以使用@WebFilter注解方式或xml方式配置过滤器
过滤器链:多个过滤器的组合
过滤器优先级
优先级:
如果为注解的话,是按照类全名称的字符串顺序决定作用顺序
如果web.xml,按照filter-mapping注册顺序,从上往下
web.xml配置高于注解方式
如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次

拦截器跟过滤器区别:
1.执行顺序有区别
请求->tomcat->过滤器->Servlet(DispatchServlet)->拦截器->Controller
2.过滤器基于函数回调,拦截器基于java反射(因为aop)
3.过滤器依赖于servlet容器(tomcat),而拦截器依赖于springmvc
4.过滤器几乎对所有请求都可以起作用,而拦截器只能对springmvc(controller)请求起作用。
5.拦截器可以访问方法的上下文,而过滤器不行。

Listener
主要用来监听Application、Session、Request三个对象的创建、销毁并对对象的属性进行增、删、改。
Listener的分类
Listener主要分为三类八种
在这里插入图片描述 比如servletContextListener,监听ServletContext对象的创建和销毁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值