目录
12.BeanFactory和ApplicationContext
1.spring的理解
什么是spring?
spring是一款轻量级的,非侵入式的具有ioc和aop功能的容器框架,目的是简化企业应用的开发,让开发者只需要关注业务实现
2.spring的优缺点
-
低侵入式设计,对源代码不会造成污染
-
aop可以实现横向编程,对通用任务比如日志,异常捕获进行集中式管理
-
支持对主流的框架的集成
缺点
-
过多的配置信息显得较为繁琐
-
依赖较多,当我们不想使用spring框架时,解构非常的复杂
3.IOC和AOP
IOC意为控制反转,将创建对象的控制权交给spring框架,由spring框架来负责对象的生命周期(创建,销毁...)
当以前我们需要创建对象时,需要手动去new对象,使用后还需要手动销毁(Connection),这个对象始终和其他的接口或者类耦合在一起,而IOC则是由专门的容器进行来进行创建对象,所有的类在spring容器中进行注册,当我们需要用到某个类时,spring会主动给你,控制对象的生命周期不再是由引用对象决定,引用对象只需要被动接受即可。
DI:依赖注入是实现IOC的一种方法,在程序运行时,动态的向某个对象提供它所需要的其他对象,通过反射实现,主要有三种注入方式
-
构造器注入
-
set注入(重点):要求被注入的对象一定要有set方法,其中又有常量注入,List注入,数组注入等等...
-
拓展注入:主要分为p命名空间(调用无参)和c命名空间(调用有参)
AOP:面向切面编程
用于那些与业务逻辑无关但又必不可少的代码,将这些代码抽取出来并封装成一个可重用的模块,降低模块之间的耦合性,提高系统的可维护性,可用于权限认证,日志,统一异常处理等。
AOP的主要思想用到了代理模式,而代理模式由分为静态代理和动态代理,静态代理的代理类是固定的,而AOP中的代理类分为两类:
- 基于接口的JDK代理:实现了InvocationHandler接口并且重写invoke方法,proxy类会生成最终的代理类
java
public Object getProxy(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(object,args);
}
- 基于类的CGlib代理:采用动态字节码生成技术,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
4.Bean的自动装配
Byname
通过Bean的属性名字进行自动装配,在配置文档中查找一个与将要装配的属性同样名字的Bean
ByType
XML中正好有一个与属性类型一样的Bean,就自动装配这个属性。如果存在多个这样的Bean,就抛出一个异常
构造器
利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
no
不进行自动配置,通过ref属性指定
autodetect
自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
5.bean和new的对象有什么区别
-
创建方式:bean对象是由ioc机制创建,new对象是由new关键字创建
-
生命周期:bean对象的生命周期可以通过spring的配置进行控制,而new对象的生命周期是由垃圾回收机制控制
-
对象池:bean对象使用完毕后不会被销毁,而是会放进对象池中以备下次使用,new对象是强引用类型,如果不在使用GC是无法回收它的,久而久之会造成内存泄漏
6.AOP中的术语和通知
术语
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知 执行的 "地点"的定义。
-
连接点(JointPoint):与切入点匹配的执行点。
通知
-
前置通知
-
后置通知
-
异常通知
-
环绕通知:在目标执行的前后进行增强逻辑
-
最终通知:目标方法执行后进行增强无论有没有异常都会执行
7.实现AOP的方式
通过springAPI实现
-
编写逻辑
-
编写实现类实现对应接口
-
在xml中配置
自定义类实现
-
编写切入类
-
xml中配置
注解实现
8.Spring中的事务管理
是指一组数据库的操作,将他们是为一个逻辑单元进行执行,要么全部成功,要么全部失败,具有ACID特性
编程式事务
将事务管理代码嵌入到业务方法中,在代码中手动提交和回滚
声明式事务
通过AOP实现,只需要对在事物管理中运行的方法添加注解标签声明即可,有xml方式和注解方式实现
9.声明式事务的失效情况
-
数据库的引擎不支持事务
-
@Transactional 应用在非 public 修饰的方法上
-
异常被try-catch捕获
-
出现了编译期异常
10.springmvc的运行流程
-
用户请求到达先前端控制器DispatcherServlet
-
DispatcherServlet收到请求后去调用HandlerMapping(处理器映射器)
-
HandlerMapping根据url找到后端具体的Handler⽣成处理器对象及处理器拦截器(如果 有则⽣成)⼀并返回DispatcherServlet
-
DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
-
Handler执行完毕后会返回一个ModelAndView,再次返回给DispatcherServlet
-
前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
-
视图解析器向前端控制器返回View
-
前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
11.spring和springboot的区别
总体来说,springboot是spring框架的拓展,旨在提供更简洁,更快速的开发体验,同时还保留了spring强大的生态系统和丰富的功能
-
springboot采用了约定大于配置的理念,大大简化了spring的初期搭建和后期维护的工作,它提供了大量的自动配置,开发者不需要进行繁琐的xml配置就可以专注于核心业务的开发。
-
springboot内置了tomcat等应用服务器,让项目的部署也变得过更加方便
-
springboot还提供了各种的starter组件,方便集成各种的框架和中间件
12.BeanFactory和ApplicationContext
1.ApplicationContext间接集成BeanFactory
- BeanFactory才是spring的核心容器,ApplicationContext在BeanFactory上做了拓展,也就是说BeanFactory是ApplicationContext的一个成员变量,getBean功能是由BeanFactory提供
java
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
加载方式
BeanFactory采用了延迟加载来注入bean,这样我们在没有使用到某个bean之前就不能发现存在的配置问题
ApplicationContext在容器启动时,一次性创建了所有的bean在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
13.Bean的作用域
-
singleton:单例,spring中的bean默认是单例的
-
prototype:原型,每次请求都会创建一个新的bean
-
request:每次请求创建一个实例,请求完成后bean会失效,被垃圾回收
-
session:同一个会话共享一个实例,不同的会话使用不同的实例
-
global-session:全局作用域,所有的会话共享一个实例
14.springbean的生命周期
-
实例化:创建一个对象
-
属性注入:为对象中关联属性赋值,也就是常说的IOC注入。
-
初始化:检测我们的类是否实现某些接口,如果实现了,就会执行相应的方法,aop额外功能的增强也是在初始化环境中进行的.
-
将bean对象放入容器
-
销毁:如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
15.bean是线程安全的吗
对于prototype
每次都创建一个新对象,线程之间不存在bean共享,所以是线程安全的
对于singleton所有的线程都会共享一个bean对象,存在线程安全问题
分为有状态和无状态两种情况:
有状态:有数据存储功能例如包含成员变量,存在线程安全问题
无状态:线程中的操作不会对 Bean 的成员执行查询以外的操作,那么这个单例 Bean 是线程安全的,例如Controller,Service,Dao,他们只关注方法本身
解决:1. 将作用域设置为prototype
- 使用ThreadLocal为每一个线程设置一个副本,不同线程只能操作自己的线程副本
16.Bean的循环依赖
采用spring的三级缓存主要思想是将bean的初始化和bean的属性注入相分开
-
一级缓存:初始化完成的bean
-
二级缓存:没有完成初始化的半成品的bean
-
三级缓存:放的是用来创建初始化某个bean的工厂
流程
-
初始化beanA,此时需要注入beanB,没有找到B,把beanA交给一个工厂对象并存入三级缓存中
-
查找beanB也不存在,将B交给一个工厂
-
由于B需要A,此时在三级缓存中找到A对象,注入给B,将B放入二级缓存中,从三级缓存删除B工厂对象
-
完成B的初始化,放入一级缓存中
-
将完整的B注入给A,完成A的初始化
17.过滤器和拦截器
-
运行顺序不同:Filter是Servlet容器接收到请求之后,但是在Servlet被调用之前运行的,拦截器是Servlet被调用之后,但响应被发送到客户端之前运行的
-
配置方式不同:过滤器是在web.xml中配置,拦截器是在spring配置文件中或使用注解配置
-
Filter依赖于Servlet容器,拦截器则是基于反射机制,在某个字段被访问之前进行拦截
18.spring中用到的设计模式
-
工厂模式:通过BeanFactory和ApplicationContext来创建对象
-
单例模式:bean的默认作用域就是单例
-
代理模式:aop的底层实现就用到了JDK的动态代理和Cglib字节码生成
-
模板方法模式:例如jdbcTemplate,RestTemplate
-
适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式
19.spring的常用注解
-
@RestController
-
@RequstMapping(路径参数)
-
@RequsetParam("前端post请求中的参数名")后端的参数名,作用:将前端传回来的参数和后端的参数进行绑定
-
@DataTimeFormat:日期参数
-
@RequestBody :json形式参数
-
@PathVariable 路径形式参数
-
@Component:将类的对象交给IOC容器管理
-
@Autowired:自动装配
-
@Controller:控制层(RestController中已经包括)
-
@Service:业务层
-
@Repository:数据层
-
@Primary:提高bean优先级
-
@Resource:java中提供的注解(name= " ")
-
@Qualifier:标记使用的bean的名字
-
@Mapper:用于持久层
-
@Options:自增主键回填
-
@Results:使数据库列名和属性名进行匹配(dept_id---->deptId不推荐)建议开启驼峰映射
@Autowired和@Resource
(1)@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。可以用在构造器、方法、参数、成员变量上
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。用在类、成员变量和方法上。
20.springboot自动装配原理
在启动时,首先会对yml和pom文件进行解析,获取项目中的第三方组件,然后读取山spring.factroies中的spring支持的配置类
@SpringBootApplication包含了3个注解标签
-
@SpringBootConfiguration:注解标注在哪个类上,就表示当前这个类是一个配置类,而配置类也是spring容器中的组件
-
@EnableAutoConfiguration这个注解是开启自动配置的功能,里面包含了两个注解
-
@AutoConfigurationPackage:这个注解的作用说白了就是将主配置类所在包以及子包里面的所有组件扫描并加载到spring的容器中,
-
@Import(AutoConfigurationImportSelector.class)就是将需要自动装配的类以全类名的方式返回
3.@ComponentScan:扫描当前包以及子包