Spring基础知识总结

212 阅读12分钟

Spring基础

Spring是什么?

Spring是非入侵式的支持AOC和IOP的Java框架。

Spring的核心模块?

Spring有七个核心模块:

Spring core:是Spring框架的基础,提供了IOC和DI;

Spring context:是上下文容器封装;

Spring AOP:实现了Spring的面向切面编程;

Spring web:支持web应用的开发;

Spring mvc:支持基于MVC的web开发;

Spring DAO:提供了JDBC的抽象层;

Spring ORM(Object Relational Mapping):集成了常见的ORM框架,Spring + Hibernate、Spring + iBatis、Spring + JDO ;

Spring 常见的注解?

从容器:

  • bean:声明该方法的返回值为一个Bean,被Spring统一管理;
  • Component:声明为组件,成为被管理的Bean;元注解。
  • Configuration:声明为配置类,相当于一个XML;
  • Service:用于业务逻辑层;
  • Repository:数据访问层;
  • Autowired:自动Bytype装配;
  • Qualifier:和上一个注解一起使用,指定Bean;
  • value:用在字段上注入,一般是将application.properties默认的属性注入到变量。

从web:

  • RestController:组合注解,返回的数据是整个页面,比如JSON格式;
  • Controller:返回MVC中的视图
  • Requestbody:允许request参数在request体中;
  • ResponseBodyl:允许response的参数在response体中;
  • RequestMapping,在Rustful风格中还有,putMapping,getMapping,deleteMapping;
  • PathVariable:用于接收路径参数。

AOP:

  • After:方法之前执行;
  • Before:方法之后执行;
  • Around:前后都执行;
  • cutPoint:定义切面。

Spring使用了什么代理模式?

  • 单例模式:每一个Bean都是单例的;
  • 工厂模式:bean由工厂统一生产;
  • 代理模式:Bean是通过代理模式生产;
  • 模板模式:封装了一些常用的地方,JDBC;
  • 适配器模式:加强的AOP
  • 策略模式:同一个类有多种实现方式,比如Resource,可以用类、字节、或者直接File。

IOC

什么是IOC?

IOC也就是控制反转,在Java中我们开始创建对象需要通过new的方式,而IOC也就是容器,由容器来负责对象的生命周期和对象间的关系。

什么是Bean?一个类声明为 Bean 的注解有哪些?

Bean就是被IOC容器统一管理的对象.

相关的注解有,Compontent(组件)、Service(服务层)、Repository(持久层)、Controller(控制层)等。

Component和Bean的区别?

位置不同:Component是在类上注解,Bean是在方法上注解;

扫描方法:Component是还要配合注解CompontentScan注解(路径)扫描才能生效,Bean告知Spring这是某个类的实例,需要的时候调用;

适用范围:Bean更加灵活,比如说对第三方类库的类只能使用Bean.

注入Bean的注解有哪几种?前两种的区别在哪?

注入bean的注解有Autowired、Resource、Inject;

区别:

  • Autowired是Spring提供的注解,默认为Bytype进行注入,可以通过配合Qualifier注解,实现Byname;如果使用默认的Bytype,但是同一个接口有多种实现,使用就会报错.
  • Resource是JDK,annotation包下的提供的注解,默认是Byname,也可以更改为bytype,他常见的两个属性就是通过name和type.

Bean的定义和依赖定义的方法有哪些?Bean的作用域?怎么配置作用域的?

方法:编码形式,配置文件,注解;

Bean的作用域:

  • singleton:最常见的,容器中只有唯一的一个Bean实例,默认都是单例bean,;
  • prototype:(原型模式)每一个获取的bean,都是一个全新的Bean;

以下在Web应用中:

  • session:每一个新的session的http请求,都会生成一个会话Bean;
  • cookie:每一个cookie的http请求,都会生成一个Bean;
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效;
  • websocket:网络会话发起的时候,也会生成一个Bean.

怎么配置作用域:

  • 在XML文件中,配置scope属性;
<bean id="..." class="..." scope="singleton"></bean>
  • 在Bean上增加Scope注解
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}

Bean的线程安全吗?

说安全与否,得先看他的作用域是哪一种,常见的singleton和prototype来说:

prototype是线程安全的,因为,每一个线程获取到的bean都是不同的,不存在资源竞争问题;

singleton是线程不安全的,因为IOC容器中只有一个bean,只要这个bean是有状态的(属性有set方法),那么自然会遇到线程不安全的问题,对于如何解决的话,一是bean无状态,在实际运用中显然是不可取得,二是在类中中加入threadlocal,将有状态的变量放于Threadlocal中.

Bean的生命周期?

这个得分为四个周期:

  • 实例化:将bean实例化;
  • 属性赋值:将bean的属性注入其中;
  • 初始化:初始化分为几步,①检查Aware相关接口并且设置依赖;②调用BeanPostProcessor方法,进行前置处理;③是否实现initailizinBean接口;④是否重写init-method方法;⑤调用BeanPostProcessor,进行后置处理(⑥注册Destruction销毁方法的回调接口)]
  • 使用中.......
  • 销毁:①是否实现disposableBean方法②是否实现destory-method方法

BeanFactory和ApplicantContext区别?

区别:

  • BeanFactory是Spring中的一个基础接口,完成了bean的获取和生命周期的控制,ApplicantContext继承了BeanFactory,有BeanFactory的所用功能,同时进行了功能扩展;
  • BeanFactory是懒加载,需要用bean的是否才加载bean,而ApplicantContext则是启动就加载完bean;
  • ApplicantContext相比BeanFactory还实现了很多接口比如:
    • MessageSource用于国际规则配置,
    • Environment用于nocas在注册中心的使用,
    • EventPublish:实现时间相关的设置,用于发送消息和响应,
    • Resource:获取访问资源,比如在classpath下的项目配置文件。

容器启动过程?

TODO

容器启动阶段,就是加载和解析配置文件,然后装配到Bean中,之后进行Bean的实例化、属性注入和初始化

有哪些依赖注入的方式?

通过构造器注入,通过工厂注入,通过setter方法注入.

什么是自动装配?有哪些自动自动装配?

  • bytype:通过类型;
  • byname:通过类名字;
  • constructor;通过构造器注入;
  • autodetect(自省机制):自行判断是根据类型注入还是构造器注入,提供了默认的了构造函数则采用bytype,反之;

什么解决循环依赖?二级缓存行不行?()

解决循环依赖之前,先得明确什么是循环依赖,就是两个以上bean之间的环形依赖形成。一般是出现在singleton,也就是单例bean中,如果是prototype原型模式,循环依赖会创建大量对象,知道报错。

通过三级缓存解决:

  • 第一层缓存:singletonObjects,已经完成实例化和初始化的bean;
  • 第二层缓存:earlysingletonObjects,早期曝光对象,用于保存实例化完成的bean的实例;
  • 第三层缓存,singletonFactories,早期曝光对象工厂,用于保存bean创建工厂。

以AB循环依赖为例:

  • A实例化对象后发现,依赖于B,然后通过A创建实例工厂放在三级缓存中,也就是singletonFactories中。如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。;
  • 对B进行实例化,然后进行属性注入的时候,发现需要A,从一级缓存向下三级缓存找,找到三级缓存中的A工厂;
  • 如果A是代理对象则注入代理对象,如果A不是代理对象,则直接注入原本的值,然后早期曝光对象A从三级缓存放到二级缓存,删除三级缓存中的A;
  • 这时候B顺利完成实例化、属性注入和初始化,放到一级缓存中;
  • A继续属性注入,从以及缓存中找到B顺利注意,完成剩下的步骤。

二级缓存不可以!

  • 如果仅为了解决循环依赖问题,二级缓存也够用了;之所以需要三级缓存因为和AOP有关,如果直接用二级缓存,在实例化后,那怕是代理对象也需要完成代理,但是在Spring中,Spring设计要求在后置处理的时候在才进行AOP实例。
  • (如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。)

www.cnblogs.com/daimzh/p/13…

AOP

说说什么是AOP?平时有没有使用到AOP?

AOP面向切面编程,目的就是就公用的业务逻辑单独抽出来,让专门业务逻辑更加清晰可见,降低耦合,有利于扩展和维护,比如说缓存、日志等。通常可以通过Spring AOP或者AspectJ实现。

以日志为例,引入 AOP 依赖,定义一个mylog的注解,然后另外起一个类,在上面用注解声明为(组件+切面),然后内部将注解作为切面,在下一个方法Before打印请求的信息,再下一个方法After打印结束字样,然后Around注解声明前后的时间。

说说对两种动态代理的理解?

JDK代理:

  • 要求被代理的类实现接口InvocationHander,通过反射调用目标代码,在此过程,可能包装逻辑,对目标进行前置后置处理;
  • 代理的发生是在被代理生成的类。

CGLIB代理:

  • 被代理的类可以不用实现接口,通过第三方类库ASM实现,原理通过字节码处理框架;
  • 原理是,通过字节码技术为类创建一个子类,并且在子类中,拦截父类方法的调用,顺势织入横切逻辑。
  • 代理发生在继承的类,对于final方法无法进行代理。

Spring AOP和AspectJ AOP的区别?

Spring AOP:

  • 基于动态代理,运行时加强;
  • 纯Java实现,适用于Spring的容器
  • 代理性能对比AspectJ AOP略差,因为要在原本的类的基础上新建代理对象增加栈深。

AspectJ AOP:

  • 基于功能强大的AOP框架,静态织入,编译时加强;
  • 可以整合框架也可以整合到其他框架,需要使用单独的编译器AJC;
  • 发生在编译织入,编译后织入,类加载后织入,性能好。

AspectJ定义的通知类型有哪些?

After,Before,AfterThrowing(异常通知),AfterReturning(返回通知),Around;

多个切面的执行顺序怎么控制?

通过@Order注解实现;

通过实现getOreder,值越小,优先级越高。

事务

事务的种类

声明式(常用)和编程式

事务的隔离级别

一般情况下,和数据库的事务隔离级别相同; 举例而言,如果是Mysql那么事务的隔离级别是可重复读。

事务的传播机制?

七种,常见的两种,

requested:有一个新事务,如果原本已有事务,就加入其中,否则新建一个事务;

request_new:无论情况,直接新建一个事务;

never:不支持事务,会报异常;

no_suppor:不支持事务,会挂起。

事务实现原理

  • AOP动态代理,生成代理对象;
  • 增强事务,如果调用目标方法,环绕增强,实现事务的开启、提交和回滚

声明式事务什么时候失效?

  • 没有publice修饰失效
  • 被final修饰,可能失效,因为CGLIB代理
  • 调用同一个的类的方法,比如我调用了A方法,A方法调用了同类中的B方法,B方法被有Transactional修饰,也会失效。因为,只有当前事务方法,被当前以外的事务方法调用时候,才会被Spring生成代理对象
  • 事务的传播行为设置为不支持会失效;
  • 默认回滚是,error或者unchecked 异常(运行时异常),如果出现自定义异常又没有声明也会失效

Spring MVC

谈谈对Spring MVC的了解?

MVC是一种软件架构模式,Spring MVC是一个优秀的MVC框架,可以进行更加简洁的web开发,在该框架下,一般把后端分为Controller层,Service层,Dao数据处理层。

Spring MVC的流程?

  • 首先一个ruquest请求过来,先发送到前置处理器也是中央处理器DispatcherServlet;
  • 然后调用处理器映射器,查询需要执行哪些controller,并返回给DispatcherServlet;
  • 然后DispatcherServlet调用处理器适配器,由处理器适配器去然后执行器执行controller并且返回viewandModel给DispatcherServlet;
  • DispatcherServlet调用视图分析器,分析逻辑视图转为物理视图,再返回给DispatcherServlet;
  • DispatcherServlet将数据填充到视图,返回给客户端。

Spring boot(TODO)

Spring boot的优点

  • 快速创建应用程序,快速整合常用依赖;
  • 相比于spring,spring boot根据约定大于配置的核心思想,相比于Spring各种xml配置文件,简化成注解或者yml
  • 集合了Tomcat,Jetty容器,不用自己配置;
  • 提供了一些现有的功能,比如量度工具。

SpringBootApplication注解

这是一个组合注解;

CompScan:组件扫描;

Enable:支持自动装配

Con:允许上下文注册额外的bean;

自动装配的原理

引入第三方starter包后,自动将第三方的组件的bean加载到IOC容器中以供使用;

这个过程主要是通过Spring Boot的自动装配,通过读取在。MATE-INF/目录下spring-factories文件,根据k-v关系,自动加载满足AutoConfiguration类中的bean,完成自动装配。

如何写一个starter

  • 首先导入依赖spring-boot-starter;
  • 编写配置文件,@ConfigurationProperties(prefix = "hello");
  • 创建自动配置的类,@Configuration,@EnableConfigurationProperties(HelloProperties.class)
  • 然后在/resources/META-INF/spring.factories路径下,声明自动装配类;