Spring面试题

101 阅读7分钟

Spring面试题

1、Ioc容器的加载过程?
Ioc容器用于对Bean的管理。首先Spring扫描xml文件或者注解或者JavaConfig,根据类的定义生成BeanDefinition,Ioc容器的getBean方法中,会遍历所有的BeanDefinition,生成Bean。通过的反射的方式对Bean进行实例化,然后进行依赖注入(这里涉及到了三级缓存),最后进行初始化,将成熟的Bean放到SingletonObjects中。SingletonObjects其实是个map,key是BeanName,value是Bean。

2、所有的Bean在程序启动时都会创建出来吗?
在程序启动时创建出来的Bean要满足几个条件:
(1)不是懒加载;
(2)作用域是单例;
(3)自动配置类的自动配置方式

3、Bean的生命周期?
Bean首先会被实例化,这个过程就是通过反射的方式创建出纯净的Bean;然后进行依赖注入,根据Autowired、Value等注解,对Bean的属性赋值;然后是初始化,初始化就是调用初始化方法,例如被注解PostConstruct修饰的方法,或者类实现InitializingBean接口的afterPropertiesSet方法,还有在@Bean注解中对InitMethod属性赋值指定初始化方法。还有就是Bean的销毁,例如类实现DisposableBean接口的destroy方法,被注解的PreDestroy修饰的方法,还有在@Bean注解中对InitDestroy属性赋值指定初始化方法。

4、什么是循环依赖,如何解决? 循环依赖是指两个或者多个Bean互为对方的属性。Spring通过三级缓存解决循环依赖。一级缓存中存放的是成熟的Bean,二级缓存中存放的是纯净的Bean,三级缓存中存放的是Bean工厂,用于生产Bean。A依赖于B,B也依赖于A时,假设先创建A,创建出纯净的A后,放到二级缓存中,发现A依赖于B,就去创建B。创建出纯净的B,放到二级缓存后,发现B也依赖于A,此时就把二级缓存中的A依赖注入给B,再把成熟的B放到三级缓存。最后将成熟的B依赖注入给A,将A也放到三级缓存中。

5、Ioc容器加载时的扩展点?
(1)在注册BeanDefinition时存在两个扩展点。可以通过实现BeanDefinitionRegistryPostProcessor接口中的postProcessDefinitionRegistry方法以及postProcessBeanFactory方法。postProcessDefinitionRegistry方法是在BeanDefinition注册前执行,可以用来注册想要的BeanDefinition;postProcessBeanFactory方法是在所有BeanDefinition注册完成后执行,可以对已注册的BeanDefinition进行修改。
(2)在Bean的初始化阶段有许多扩展点。实现XXXAware接口的SetXXXAware方法,这是一类方法,这些方法可以拿到Ioc容器加载过程中生成的BeanName、BeanFactory等。还有就是一些Bean生命周期的回调:实现BeanPostProcessor接口的postProcessBeforeInitialization方法,这个方法在初始化方法之前执行;实现BeanPostProcessor接口的postProcessAfterInitialization方法,这个方法在初始化方法之后执行。

6、什么是FactoryBean?
FactoryBean是一个接口,里面有getObject方法、getObjectType方法和isSingleton方法。假设类A实现了FactoryBean的getObject方法,当我们使用Ioc容器的getBean("a")方法时,获取到的是FactoryBean中getObject方法生成的Bean。想要获取原本的A对象,应该写getBean("&a")。

7、什么是AOP?
AOP中文翻译是面向切面编程,是通过动态代理实现的。在程序启动类上添加@EnableAspectJAutoProxy注解启动AOP。这个注解会注册一个Bean的后置处理器,这个后置处理器会去解析切面,将切面中的切点、通知等信息封装成一个个advisor放到list中。当Ioc容器创建Bean时,在初始化阶段后,有切面的Bean会通过动态代理生成代理对象(动态代理有两种方式,jdk动态代理和cglib动态代理)。在调用增强方法时,会拿到动态代理对象,以调用链的方式依次执行通知代码。

8、jdk动态代理与cglib动态代理的区别?
jdk动态代理是实现接口的方式,cglib动态代理是继承的方式。所以没有实现接口的类是无法使用jdk动态代理的,无法被继承的类是不能使用cglib动态代理的。还有,不是实现接口的类都能用jdk动态代理,例如实现的接口是Bean生命周期回调接口InitializingBean等,或者实现的接口中没有方法,那么也是不能使用jdk动态代理的。

9、AOP什么情况下会失效?
AOP在内部调用的情况下会失效。所谓内部调用是指一个类的成员方法中又调用了这个类的成员方法,而且使用this去调用。

10、什么是Spring事务?
通过@EnableTransactionManagement注解开启Spring事务。Spring事务是通过AOP实现的。对使用了@Transactional注解类创建了代理对象,代理对象中的方法开启了事务。

11、Spring事务失效?
Spring事务是通过AOP实现的,其失效场景与AOP失效一样,内部调用。其实可以通过编程式事务的方式手动开启、提交和回滚事务来处理内部调用的情况。或者更复杂一些,使用分布式事务。

12、Spring MVC的工作流程?
当一个网络请求过来,首先会经过过滤器处理,通过过滤器会到前端控制器DispatcherServlet。DispatcherServlet会根据请求的URL和方法在HandlerMapping中找到对应的HandlerExcutionChain。HandlerExcutionChain中有拦截器和处理器,有HandlerAdapter处理Handler,在Handler执行后端代码之前,先执行拦截器。等服务器返回ModelAndView后,先经过拦截器,然后经过视图解析器,解析视图,然后进行视图渲染,最后再经过过滤器,返回给前端。

13、Spring MVC处理AJAX请求?
Spring MVC自带的Jackson有消息转换器可以对json数据格式的请求和响应做消息转换。也可以使用fastjson提供的消息转换器完成此功能。

14、Spring MVC父子容器?
Spring在启动时会创建一个容器,当Spring MVC在启动时,也会创建一个容器,并且会将Spring的容器当做父容器,自己作为子容器。父容器中存储的是service和dao层的Bean,子容器中存储的是controller层的Bean。子容器可以访问父容器中的Bean,但是父容器不可访问子容器中的Bean。

15、为什么分父子容器?
(1)单一职责原则,父子容器分工比较明确
(2)在Spring MVC之前还有一个web框架Structs,使用父子容器架构更方便框架切换

16、Spring事务的传播行为?

image.png (1)REQUIRED(默认):外部不存在事务,开启新事务;外部存在事务,融入外部事务
(2)SUPPORTS:外部不存在事务,不开启事务;外部存在事务,融入外部事务
(3)REQUIRED_NEW:外部不存在事务,开启新事务;外部存在事务,也开启新事务
(4)NOT_SUPPORTED:外部不存在事务,不开启新事务;外部存在事务,不开启新事物,也不融入外部事务,反正就是不使用事务。这种和不用事务注解修饰的方法是一样的
(5)NEVER:外部不存在事务,不开启新事务;外部存在事务,抛出异常
(6)MANDATORY:外部不存在事务,抛出异常;外部存在事务,融入外部事务
(7)NESTED:外部不存在事务,开启新事务;外部存在事务,融入外部事务。外层事务影响内层,内层事务不会影响外层