Spring面试系列-03

2022年7月17日
大约 13 分钟

Spring面试系列-03

1. Spring AOP 中关注点和横切关注点有什么不同?

关注点

关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。

关注点可以被定义为:想实现以解决特定业务问题的方法。

例如,在所有电子商务应用中不同的关注点(或者模块)可能是库存管理、航运管理、用户管理等。

横切关注点

横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。

2. Spring AOP 中切入点和连接点什么关系?

连接点是个虚的概念,可简单理解为切入点的集合,它只是对应用程序的所有需要进行插入切面的一个统称。

每个切入点都对应具体的连接点,在运行期Spring就是根据这些切入点的定义,将通知或者拦截器插入到具体的连接点上。

3. Spring AOP 代理是什么?

代理是使用非常广泛的设计模式。简单来说,代理是一个看其他像另一个对象的对象,但它添加了一些特殊的功能。

Spring AOP是基于代理实现的。AOP代理是一个由AOP框架创建的用于在运行时实现切面协议的对象。

Spring AOP默认为AOP代理使用标准的JDK 动态代理。这使得任何接口(或者接口的集合)可以被代理。

Spring AOP也可以使用CGLIB代理。这对代理类而不是接口是必须的。

如果业务对象没有实现任何接口那么默认使用CGLIB。

4. Java 中什么是 Aspect 切面?

AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。

比如,一个日志模块可以被称作日志的AOP切面。

根据需求的不同,一个应用程序可以有若干切面。

在Spring AOP中,切面通过带有@Aspect注解的类实现。

5. BeanFactory 和 ApplicationContext 有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。

1、BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。

ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

1)继承MessageSource,因此支持国际化。

2)资源文件访问,如URL和文件(ResourceLoader)。

3)载入多个(有继承关系)上下文(即同时加载多个配置文件) ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

4)提供在监听器中注册bean的事件。

2、BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

ApplicationContext是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。

ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。

3、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是BeanFactory需要手动注册,而ApplicationContext则是自动注册。

4、BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

6. Spring 中有几种不同类型的自动代理?

BeanNameAutoProxyCreator

DefaultAdvisorAutoProxyCreator

Metadata autoproxying

7. Spring 中什么是目标对象?

被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。

8. Spring 框架中事务管理有哪些优点?

Spring框架事务管理为不同的事务API,如JTA、JDBC、Hibernate、JPA和JDO,提供一个不变的编程模式。

Spring框架为编程式事务管理提供了一套简单的API而不是一些复杂的事务API。

Spring框架支持声明式事务管理。

Spring框架和Spring各种数据访问抽象层很好得集成。

9. JDK 动态代理和 CGLIB 动态代理有什么区别?

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

1、JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

2、如果代理类没有实现InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

InvocationHandler中的

invoke(Object proxy,Method method,Object[] args);

proxy是最终生成的代理实例;method是被代理目标实例的某个具体方法;args是被代理目标实例某个方法的具体入参,在方法反射调用时使用。

10. Spring AOP 和 AspectJ AOP 有什么区别?

AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

11. Spring 中 ApplicationContext 通常的实现是什么?

FileSystemXmlApplicationContext

此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。

ClassPathXmlApplicationContext

此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。

WebXmlApplicationContext

此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

12. Spring Native 框架是什么?

Spring团队发布Spring Native Beta版。

通过Spring Native,Spring应用将有机会以GraalVM原生镜像的方式运行。

为了更好地支持原生运行,Spring Native提供了Maven和Gradle插件,并且提供了优化原生配置的注解。

13. Spring Native 有什么优缺点?

Spring Native优点

1)立即启动,一般启动时间小于100ms;

2)更低的内存消耗;

3)独立部署,不再需要JVM;

4)同样的峰值性能要比JVM消耗的内存小。

Spring Native缺点

1)构建时间长;

2)只支持新的Springboot版本(Spring Native 0.9.0 supports Spring Boot 2.4.3, Spring Native 0.9.1 will support Spring Boot 2.4.4, etc.)

14. Spring Native 和 JVM 有什么区别?

欢迎大家关注微信公众号: Java精选 ,专注分享前沿资讯,BATJ 大厂面试题解读,架构技术干货,微服务、高可用等架构设计,10年开发老兵帮你少走弯路,欢迎各领域程序员交流学习!

此类面试题只能在微信小程序: Java精选面试题 ,查阅全部内容,感谢支持!

15. 什么是 Spring 配置文件?

Spring配置文件是一个XML文件。此文件包含类信息,并描述了这些类是如何配置和相互引入的。

16. Spring 中如何定义 Bean 的范围?

在Spring中定义一个时,我们也可以为bean声明一个范围。它可以通过bean定义中的scope属性定义。

例如,当Spring每次需要生成一个新的bean实例时,bean的scope属性就是原型。另一方面,当每次需要Spring都必须返回相同的bean实例时,bean的scope属性必须设置为singleton。

注:bean的scope属性有prototype,singleton,request, session几个属性

17. Spring 框架中有哪些不同类型的事件?

Spring提供了以下5种标准的事件:

上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

18. Spring 应用程序有哪些不同组件?

Spring 应用一般有以下组件:

  • 接口 - 定义功能。

  • Bean类 - 它包含属性,setter和getter方法,函数等。

  • Bean配置文件 - 包含类的信息以及如何配置它们。

  • Spring面向切面编程(AOP) - 提供面向切面编程的功能。

  • 用户程序 - 它使用接口。

19. Spring 如何设计容器的?BeanFactory 和 ApplicationContext 两者关系?

Spring 作者 Rod Johnson 设计了两个接口用以表示容器。

  • BeanFactory

  • ApplicationContext

BeanFactory可以理解为就是个HashMap,Key是BeanName,Value是Bean实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。

ApplicationContext可以称之为 “高级容器”。因为它比BeanFactory多了更多的功能。它继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如JSP tag的支持),对BeanFactory多了工具级别的支持等待。所以他的名称已经不是BeanFactory之类的工厂,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个refresh方法,此方法是所有阅读Spring源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的bean。

当然,除了这两个大接口,还有其他的辅助接口,这里就不过多介绍。

BeanFactory和ApplicationContext的关系为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的ClassPathXmlApplicationContext类来展示整个容器的层级UML关系。

16434382941.jpg

有点复杂,东哥解释一下:

最上面的是BeanFactory,下面的3个绿色的,都是功能扩展接口,这里就不展开来讲,简单跳过。

看下面的隶属ApplicationContext粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承,它依赖着 “低级容器” 的getBean功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)。

通常用户看到的就是 “高级容器”。 但BeanFactory也非常够用!

左边灰色区域的是 “低级容器”, 只负载加载Bean,获取Bean。容器其他的高级功能是没有的。例如上图画的refresh刷新Bean工厂所有配置,生命周期事件回调等。

小结

说了这么多,不知道有没有理解Spring IoC?这里总结一下:IoC在Spring中,只需要低级容器就可以实现,2 个步骤:

  • 加载配置文件,解析成BeanDefinition放在Map里。

  • 调用getBean的时候,从BeanDefinition所属的Map里,拿出Class对象进行实例化,同时,如果有依赖关系,将递归调用getBean方法 —— 完成依赖注入。 上面就是Spring低级容器(BeanFactory)的IoC。

至于高级容器ApplicationContext,它包含了低级容器的功能,当他执行refresh模板方法的时候,将刷新整个容器的Bean。同时其作为高级容器,包含了太多的功能。一句话,它不仅仅是IoC。它支持不同信息源头,支持BeanFactory工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。

20. Spring 如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。