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代理。)
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路径下,声明自动装配类;