Spring阶段总结

Spring阶段总结

介绍

简单介绍一下你对Spring的理解

spring是一个一站式的轻量级的java开发框架;
两个特性:控制反转(IOC) 面向切面编程(AOP);
针对于WEB层(SpringMVC)、业务层(IOC)、持久层(jdbcTemplate)等都提供了多种配置解决方案

为什么要有Spring?

  1. 方便解耦,所有对象的创建和依赖关系的维护工作都交给Spring容器来管理。
  2. 低侵入式设计,代码污染极低,同时令代码对框架的依赖最小化。
  3. 支持AOP,减少系统重复代码,提高复用性。
  4. 声明式事务,只需要通过配置就可以完成对事务的管理。

为什么说Spring是一个容器?

用来形容它用来存储单例Bean对象这个特性。

AOP

什么是AOP?

AOP(Aspect-Oriented Programming,面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和维护性。
Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用jdk动态代理去创建代理对象,而对于没有实现接口的对象,就无法使用JDK代理,转而使用CGlib动态代理,生成一个被代理对象的子类来作为代理。
当然也可以使用Aspect(静态代理)。Spring AOP中已经集成了Aspect。

JDK动态代理和CGlib动态代理有什么区别?

JAK动态代理生成的代理类是继承了Proxy类,由于java不能多继承,只能由接口来完成对代理的实现,所以代理类必须传入被代理类实现的接口。(基于反射机制,只能针对接口编程)
cglib动态代理比JDK快,基于继承机制,继承被代理类,所以方法不要声明为final,然后重写父类方法达到增强了类的作用。需要额外引入cglib的依赖包。
JDK动态代理要求被代理类要实现接口,而cglib不需要,cglib能根据内存中为其创建子类(代理对象)

SpringAOP和AspectJ AOP有什么区别?

Spring AOP是属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理(Proxying),而AspectJ基于字节码操作(Bytecode Manipulation)。
Spring AOP已经集成了AspectJ,AspectJ应该算得上是java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更强大,但是Spring AOP相对来说更简单。
如果我们的切面比较少,那么两者性能差异不大,当切面太多的话,最好选择AspectJ,它比Spring AOP快很多。

解释下Spring AOP里面的几个名词

  • 连接点(join point):就是spring允许增强的地方,和方法有关的前前后后都是连接点。
  • 通知、增强处理(Advice):就是你想要的功能,也就是安全、事务、日志等。你给先定义好,然后再想用的地方用一下。包含切面的一段处理代码。
  • 切入点(pointcut):织入增强的连接点就叫切入点。简单说就是不是所有的连接点都有机会成为切入点,只有那些受临幸的才可以。
  • 切面(Aspect):切面是通知和切入点的结合。通知说明了干什么和什么时候干(什么时候通过规范的方法名中的before,after,around等就能知道);切入点说明了在哪干(指定到底是哪个方法)。这就是一个完整的切面定义。
  • 引入(introduction):允许我们向现有的类添加新方法属性,也被称为内部类型声明,其实就是把切面用到目标类中了。
  • 目标(target):引入所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被织入切面,而自己专注于业务本身的逻辑。由于Spring AOP 是通过运行时 代理实现的,所以这个对象永远是一个被代理对象。
  • 织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有三种方式,spring采用的是运行时。

拦截器了解吗? 有哪些应用场景?

spring拦截器是Spring AOP的一种应用,在不修改源码的情况下,执行一段代码,以增强现有方法,写自己的拦截器一般有两种方式。
1.实现HandlerInterceptor接口
2.继承HanderInterceptroAdapter抽象类
应用场景

  • 纪录接口响应时间
  • 判断用户是否登录
  • 判断用户的权限
  • 接口权限校验

IOC

谈一下你对Spring的IOC的理解

IOC称之为控制反转
之前是我们自己写代码new出来,而现在则是Spring帮我们new出来,我们不需再new。底层原理是Spring有一个容器为IOC,这个容器中开辟了很多个很重要的注解,其主要的为四大注解@Service,@Controller,@Respository,@Component。这四个注解会在他们的容器中开辟四个空间,还有一个注解为@Autowired,称之为DI,他会去找Spring容器中的Bean,如果找到了就拿出来,找不到则会报一个查找不到的错误。当Spring第一次扫描,注解会帮我们new出想要的实现类,而下次使用autowired则直接拿来用就OK了。

IOC(Inversion Of Controll,控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交给spring框架来管理。将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。
IOC容器就像一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何创建出来的。在实际项目中一个Sercive类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。
Spring时代我们一般通过XML文件来配置Bean,后来开发人员觉得用XML文件配置不太好,于是Spring Boot 注解配置就开始流行起来。

其他问题

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

设计模式:
工厂模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。
单例模式:Bean默认单例模式。
代理模式:SpringAOP的实现。
模板方法模式:大量的模板方法,例如jdbcTemplate等一些数据库操作的类。
观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
适配器模式:SpringMVC中dispatchServlet调用HandlerAdapter找到实际调用的Controller就是使用此模式,SpringAOP的增强或通知(Advice)使用到了适配器模式。

使用单例模式有什么好处?

  • 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是一个非常可观的一笔系统开销;
  • 由于new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

Spring是如何实现事务的,原理如何?

首先,事务一般是在操作数据库是提及。而Spring实现事务,本质上就是数据库对事务的支持。
1.编程式事务:在代码中硬编码(不推荐使用)
2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。

Spring事务中的隔离级别有哪几种?

常量解释
ISOLATION_DEFAULT(默认使用后端数据库默认的隔离级别,Mysql默认采用的可重复读隔离级别;
Oracle默认采用的读已提交隔离级别。
ISOLATION_READ_UNCOMMITTED(读未提交最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
ISOLATION_READ_COMMITTED(读已提交允许读取并发事务已经提交的数据,可以阻止脏读,仍有可能幻读或不可重复读。
ISOLATION_REPEATABLE_READ(可重复读对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但仍有可能幻读。
ISOLATION_SERIALIZABLE(序列化最高的隔离级别,完全服从ACID的隔离级别。所有的事务顺序执行,将严重影响程序的性能。通常情况下也不会用到该级别。

Spring事务隔离级别与MySQL InnoDB事务隔离级别冲突了会怎样?

  • Spring会在事务开始时,根据你程序中设置的隔离级别,调整数据库隔离级别与你设置的一致。
  • 当使用Serializable级别时,MySQL在执行SQL时会自动修改为select…lock in share mode,即使用共享锁。此时允许同时读,但只允许一个事务写,且锁的是行而不是整张表
  • 如果数据库不支持某种隔离级别,那么Spring设置了也无效。
  • 当使用Serializable级别时,如果两个事务读写的不是同一行,那么它们是互补影响的。如果操作同一行纪录,那么允许同时读,但如果出现一个对此行的写操作,则在事务没有提交之前,所有的读事务都会被block。

@Service注解是单例还是多例,如何做到多例?

单例,在Spring中默认是单例。我们常用的service和dao层的对象通常都是单例的,但service或dao并不一定是单例,要产生多例,则在配置文件的bean中添加 scope="prototype"

Spring中的单例bean的线程安全问题?

大部分时候,我们并没有在系统中使用多线程,所以很少人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作一个对象的时候,这个对象的非静态成员变量的写操作存在线程安全问题。
有两种常见的解决方案:
1.在bean对象中尽量避免定义可变的成员变量(不太现实)
2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。

Spring中的bean生命周期?

1、Bean容器找到配置文件中Spring Bean的定义。
2、Bean容器利用反射创建一个Bean实例。
3、如果涉及到一些属性值,利用set()方法设置一些属性值。
4、当要销毁Bean的时候,如果Bean实现DisposableBean接口,执行destory()方法。
完整版

  1. Spring IoC容器找到关于Bean的定义并实例化该Bean。
  2. Spring IoC容器对Bean进行依赖注入
  3. 如果Bean实现了BeanNameAware接口,则将该Bean的id传给setBeanName方法。
  4. 如果Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法。
  5. 如果Bean实现了BeanPostProcessor接口,则调用其postProcessBeforeInitialization方法。
  6. Bean实现了InitializingBean接口,则调用其afterPropertySet方法。
  7. 和Bean关联的BeanPostProcessors对象,则这些对象的postProcessAfterInitialization方法被调用。
  8. 销毁Bean实例时,如果Bean实现了DisposableBean接口,则调用其destroy方法。

Bean的作用域

类型说明
singleton默认值,当IoC容器一创建就会创建bean的实例,Spring中的bean默认都是单例的
prototype每次请求都会创建一个新的bean实例
request每次HTTP请求都会创建一个新的Bean,该bean仅在当前HTTP request内有效
session每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效
globalSession全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏路加

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值