100-Spring学习笔记-面试题
一、基本概念
1、Spring优点
1.1、轻量级、非入侵式:对现有的类结构没有影响
1.2、可以提供众多服务,如事务管理,WS等
1.3、对主流的框架提供了很多的集成支持,如hibernate,Struts2,像一个胶水一样,把一些好的框架粘合在一起方便实用。
1.4、使用Spring的IOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑
1.5、Spring DI 机制降低了业务对象替换的复杂性
1.6、Spring的高度可开放性,并不强制依赖于Spring,开发者可以自由选择Spring部分或全部
2、Spring缺点
2.1、没有SpringBoot好用
二、Spring类
1、ApplicationContext
1.1、FileSystemXmlApplicationContext
1.2、ClassPathXmlApplicationContext
1.3、WebXmlApplicationContext
三、SpringMVC
1、执行流程
1.1、用户发送请求至前端控制器DispatcherServlet
1.2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
1.3、处理器映射器根据请求url找到具体的处理器,生成处理对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
1.4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
1.5、执行处理器(Controller,也叫后端控制器)
1.6、Controller执行完成返回ModelAndView
1.7、HandlerAdapter将controller执行结果ModelAndView返回给DispaServlet
1.8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器
1.9、ViewReslover解析后返回具体View
1.10、DispatcherServlet对View进行渲染视图(即将模型数据填充视图中)
1.11、DispatcherServlet响应用户
2、常用注解
2.1、@Controller 用于定义控制器类
2.2、@ResponseBody 表示方法的返回结果直接写入HTTP response body中
2.3、@PathVariable 获取路径参数
2.4、@RequestParam 用在方法的参数前面
2.5、@RequestBody 返回JSON格式
2.6、@RestController 是@Controller和@ResponseBody的合集
2.7、@RequestMapping 提供理由信息,负责URL到Controller中的具体函数
2.8、@ControllerAdvice 统一处理异常
3、servlet生命周期
3.1、加载和实例化
3.2、初始化
3.3、请求处理
3.4、服务终止
四、AOP
1、基本概念
1.1、核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能“编织”在一起,这就叫AOP
1.2、让关注点代码与业务代码分离
1.3、面向切面编程就是指:对很多功能都有的重复代码抽取,再运行的时候往业务方法上动态注入“切面类代码”
1.4、应用场景:日志、事务管理、权限控制
2、实现原理
2.1、jdk动态代理
2.1.1、主要通过Proxy.newProxyInstance()和InvocationHandler这两个类和方法实现
2.1.2、实现过程
①、创建代理类proxy实现Invocation接口,重写invoke()方法:调用被代理类方法时默认调用此方法
②、将被代理类作为构造函数的参数传入代理类proxy
③、调用Proxy.newProxyInsatnce(classloader,interfaces,handler)方法生成代理类。
》
1、生成的代理类 》
1.1、$Proxy0 extends Proxy implements Person
1.2、类型为 $Proxy0
1.3、因为已经继承了Proxy,所以java动态代理只能对接口进行代理
2、代理对象会实现用户提供的这组接口,因此可以将这个代理对象强制类型转化为这组接口中的任意一个
3、通过发射生成对象
④、总结:代理类调用自已方法时,通过自身持有的中介类对象调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。
2.2、cglib
2.2.1、生成对象类型为Enhancer
2.2.2、实现原理类似于 jdk 动态代理,只是他在运行期间生成的代理对象是针对目标类扩展的子类
2.3、静态代理
2.3.1、缺点
①、如果要代理一个接口的多个实现的话需要定义不同的代理类
②、代理类和被代理类必须实现同样的接口,万一接口有变动,代理,被代理类 都得修改。
2.3.2、在编译的时候就直接生成代理类
2.4、JDK动态代理和cglib的对比
2.4.1、CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高
①、1.6和1.7的时候,CGLib更快
②、1.8的时候,jdk更快
2.4.2、CGLib在创建对象的时候所花费的时间却比JDK动态代理多
2.4.3、singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反之,则适合用JDK动态代理
2.4.4、JDK动态代理是面向接口的,CGLib动态代理是通过字节码底层继承代理类实现(如果被代理类被final关键字所修饰,那么会失败)
2.4.5、JDK生成的代理类类型是Proxy(因为继承的是Proxy),CGLIB生成的代理类类型是Enhancer类型
2.4.6、如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spring默认采用JDK动态实现机制)。
如果要被代理的对象不是个实现类,那么Spring会强制使用CGLib来实现动态代理
3、配置方式
3.1、XML方式
3.2、注解方式
3.3、基于Java类配置
通过 @Configuration 和 @Bean 这两个注解实现的
1、@Configuration作用于类上,相当于一个xml配置文件
2、@Bean作用于方法上,相当于xml配置中的<bean>
五、IOC
1、依赖注入
1.1、装配方式(依赖注入的具体行为)
1.1.1、基于注解的自动装配
①、实现方式
@Autowired byName 优先byType
注解
@Resource 优先byName byType
自动扫描(component-scan)
1.1.2、基于XML配置的显示装配
1.1.3、基于Java配置的显示装配 能够在编译时就发现错误
1.2、依赖注入的方式
1.2.1、构造器方式注入
<bean id="text" class="com.maven.Text" />
<bean id="hello" class="com.maven.Hello"><constructor-arg ref="text" /></bean>
构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
1.2.2、setter方法注入
例如:<bean id="hello" class="com.maven.Hello"><property name="text" ref="text" /></bean>。
之所以叫setter方法注入,因为这是通过找到类对应的setter方法,再进行相应的注入。
Setter方法注入是容器通过无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。
1.2.3、最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
1.3、循环依赖
1.3.1、构造器方式无法解决,只能抛出异常。
1.3.2、因为Spring容器不缓存“prototype”作用域的bean,因此无法提前暴露一个创建中的bean:多例方式无法解决,只能抛出异常。
1.3.3、通过提前暴露一个单例工厂方法,从而使其他bean能够引用到该bean/提前暴露一个正在创建中的bean:单例模式可以解决。
1.4、不用创建对象,而只需要描述它如何被创建,不在代码里直接组装组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC容器)负责把他们组装起来。
2、容器的初始化过程
1、Resource定位,指对BeanDefinition的资源定位过程。通俗地讲,就是找到定义Javabean信息的XML文件,并将其封装成Resource对象
2、BeanDefinition的载入,把用户定义好的Javabean表示为IOC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition
3、向IOC容器注册这些BeanDefinition
3、bean知识
3.1、bean的生命周期
3.1.1、实例化Bean
3.1.2、设置Bean的属性
3.1.3、检查Aware的相关接口并设置相关依赖
①、BeanNameAware
②、BeanFactoryAware
③、ApplicationContextAware
3.1.4、检查BeanPostProcessor接口并进行前置处理
3.1.5、检查Bean在Spring配置文件中配置的init-method属性并自动调用其配置的初始化方法。
》由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术
3.1.6、检查BeanPostProcessor接口并进行后置处理
3.1.7、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destory()方法
3.1.8、最后,如果这个Bean的Spring配置中配置了destory-method属性,会自动调用其配置的销毁方法
3.2、bean的作用域
3.2.1、singleton
①、Spring IOC容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一对象
②、singleton是Bean的默认作用域
③、默认情况下是容器初始化的时候创建,但也可设定运行时再初始化bean
④、DefaultSingletonBeanRegistry类里的singletonObjects哈希表保存了单例对象。
备注》Spring容器可以管理singleton作用域下bean的生命周期,在此作用域下,Spring能够精确制导bean何时被创建,何时初始化完成,以及何时销毁。
3.2.2、prototype
①、每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自已的属性和状态。
②、当容器创建了bean的实例后,bean的实例就交给了客户端的代码管理,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的bean的生命周期
③、对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。
3.2.3、request
在一次Http请求时,容器会返回该Bean的同一实例。而对不同的Htpp请求则会产生新的Bean,而且该bean仅在当前Http Request内有效
3.2.4、session
在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效。
3.2.5、global Session
在一个全局的Http Session中,容器会返回该Bean的同一实例,仅在使用portlet context时有效
3.3、bean的创建
3.3.1、进入getBean()方法
3.3.2、判断当前bean的作用域是否单例,如果是,则去对应缓存中查找,没有查找到的话则新建实例并保存。如果不是单例,则直接新建实例(createBeanInstance)
3.3.3、新建实例后再将注入属性(populateBean),并处理回调
①、创建bean
②、找到@Autowired的对象
③、创建注入对象,并赋值
4、大致流程
1、首先根据配置文件找到对应的包,读取包中的类,找到所有含有@bean,@service等注解的类,利用反射解析它们,包括解析构造器,方法,属性等等,然后封装成各种信息类收到container(其实是一个map) 里 (ioc容器初始化)
2、获取类时,首先从containere中查找是否有这个类,如果没有,则报错,如果有,则通过构造器信息将这个类new出来
3、如果这个类含有其他需要注入的属性,则进行依赖注入,如果有则还是从container找对应得解析类,new出对象,并通过之前解析出来的信息类找到setter方法(setter方法注入),然后用该方法注入对象(这就是依赖注入)。如果其中有一个类container里没有找到,则抛出异常。
4、如果有嵌套bean的情况,则通过递归解析
5、如果bean的scope是singleton,则会重用这个bean不再重新创建,将这个bean放到一个map里,每次用都先从这个map里面找。如果scope是session,则该bean会放到session里面
6、总结:通过解析xml 文件,获取到bean的属性(id,name,class,scope,属性等等)里面的内容,利用反射原理创建配置文件里类的实例对象,存入到Spring 的bean容器中。

浙公网安备 33010602011771号