常见面试题和答案汇总(1):Spring

    

目录

1. @Component和@Bean的区别是什么?

2. Spring框架中用到了哪些设计模式?

3. Spring MVC的工作原理是什么?

4. Spring中的bean生命周期?

5. BeanFactory和 ApplicationContext 有什么区别?

6. ApplicationContext通常的实现是什么?

7.Spring AOP 实现原理是什么?

8. 有哪些不同类型的IOC(依赖注入)?

9. 解释自动装配的各种模式?

10. Resource 是如何被查找、加载的?

11.Spring 事务底层原理是什么?

12. 什么是事务?

13.Spring事务中有哪几种事务传播行为?

15. Spring 事务实现方式

16. Spring框架的事务管理有哪些优点?

17.Spring事务管理的方式有几种?

18. 将一个类声明为Spring的bean的注解有哪些?

18.Spring中的单例bean的线程安全问题了解吗?

19. Spring中的bean的作用域有哪些?

20. 谈谈自己对于Spring AOP的理解

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

22. 谈谈自己对于Spring IOC的理解

23. Spring Boot手动装配有哪几种方式?

24. Spring是怎么解决循环依赖的?

25. Spring由哪些模块组成?

26. 使用Spring框架的好处是什么?

27. 什么是spring?    


【写在前面】

此文题目和答案都非原创。

是搜集了网络上分享的关于Spring面试常见问题汇总,然后又逐个搜寻了答案,整理于此。

供自学,感谢相关题目和答案的原创分享者。

1. @Component和@Bean的区别是什么?

(1)作用对象不同:@Component 注解作用于类,而@Bean注解作用于方法。

(2)@Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径,从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。

    @Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean, @Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。

(3)@Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,只能通过 @Bean来实现。

2. Spring框架中用到了哪些设计模式?

(1)代理模式:在AOP和remoting中被用的比较多。

(2)单例模式:在spring配置文件中定义的bean默认为单例模式。

(3)模板方法模式:解决代码重复问题。父类定义骨架(共同方法的实现,调用哪些方法及顺序),某些特定方法由子类实现(父类是空方法,子类继承后再重写)。

(4)前端控制器模式:spring提供了DispatcherServlet来对请求进行分发。

(5)依赖注入模式:贯穿于BeanFactory和ApplicationContext接口的核心理念。

(6)工厂模式:

------简单工厂:

实现方式:BeanFactory根据传入一个唯一的标识来获得bean对象,由工厂类根据传入的参数动态决定应该创建哪一个产品类。

实现原理:在bean容器的启动阶段,读取bean的xml配置文件,将bean元素分别转换成一个BeanDefinition对象。然后通过BeanDefinitionRegistry将这些bean注册到beanFactory中。

容器中bean的实例化阶段:主要通过反射或者CGLIB对bean进行实例化

------工厂方法:

实现方式:FactoryBean接口

实现原理:实现了FactoryBean接口的bean是一类叫做factory的bean,特点是spring会在使用getBean()调用获得该bean时,自动调用该bean的getObject()方法。返回的是这个bean.getObject()方法的返回值。

典型例子:spring与mybatis的结合:

<bean  id = "sqlSessionFactory" class = "org.mybatis.spring.SqlSessionFactoryBean" ><bean>

//最终返回的是SqlSessionFactoryBean.getObject()的返回值

(7)适配器模式:

实现方式:springmvc中的适配器HandlerAdapter

实现过程:dispatcherServlet根据HandlerMapping返回的handler,向HandlerAdapter发起请求,处理handler。HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向dispatcherServlet返回一个ModelAndView。

(8)装饰器模式:

实现方式:类名中包含Wrapper,或者是Decorator,就是装饰器模式

实质:动态地给一个对象添加一些额外的职责,比生成子类更灵活

(9)观察者模式:

实现方式:spring的事件驱动模型使用的是观察者模式,常用的地方就是listener的实现

具体实现:事件机制的实现包括事件源、事件、事件监听器:

ApplicationEvent抽象类【事件】

ApplicationListener接口【事件监听器】

ApplicationContext接口【事件源】

(10)策略模式:

实现方式:spring框架的资源访问Resource接口,是具体资源访问策略的抽象,也是所有资源访问类所实现的接口

3. Spring MVC的工作原理是什么?

(1)用户发送请求至前端控制器DispatcherServlet。

(2)DispatcherServlet收到请求调用HandlerMapping处理器映射器。

(3) 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

(4)DispatcherServlet调用HandlerAdapter处理器适配器。

(5)HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

(6)Controller执行完成返回ModelAndView。

(7)HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

(8)DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

(9)ViewReslover解析后返回具体View。

(10)DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

(11)DispatcherServlet响应用户。

组件说明:

以下组件通常使用框架提供实现:

DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 

HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。

ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

4. Spring中的bean生命周期?

Bean 的生命周期如上,描述如下:

(1)Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化。

(2)Bean实例化后对将Bean的引入和值注入到Bean的属性中。

(3)如果Bean实现了BeanNameAware接口,Spring将Bean的Id传递给setBeanName()方法。

(4)如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。

(5)如果Bean实现了ApplicationContextAware接口,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。

(6)如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

(7)如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用。

(8)如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

(9)此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。

(10)如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

5. BeanFactory和 ApplicationContext 有什么区别?

(1)BeanFactory 可以理解为含有bean集合的工厂类。BeanFactory 包含了各种bean的定义,以便在接收到客户端请求时将对应的bean实例化。

BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端的配置中解放出来。

BeanFactory还包含了bean生命周期的控制,调用客户端的初始化方法(initialization methods)和销毁方法(destruction methods)。

基础类型的 IOC 容器,提供完整的 IOC 服务支持。如果没有特殊指定,默认采用延迟初始化策略。相对来说,容器启动初期速度较快,所需资源较少。

(2)从表面上看,ApplicationContext如同BeanFactory 一样具有bean定义、bean关联关系的设置,根据请求分发bean的功能。ApplicationContext 管理的对象,在容器启动后默认全部初始化并且完成绑定。

ApplicationContext提供了一种解决文档信息的方法,一种加载文件资源的方式(如图片),他们可以向监听他们的beans发送消息。另外,容器或者容器中beans的操作,这些必须以bean工厂的编程方式处理的操作可以在应用上下文中以声明的方式处理。应用上下文实现了MessageSource,该接口用于获取本地消息,实际的实现是可选的。

但ApplicationContext在此基础上还提供了其他的功能。

  • 提供了支持国际化的文本消息
  • 统一的资源文件读取方式
  • 已在监听器中注册的bean的事件

以下是三种较常见的 ApplicationContext 实现方式:

  • ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。

ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);

  • FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。

ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);

  • XmlWebApplicationContext:由Web应用的XML文件读取上下文。

【补充】

相同点:两者都是通过xml配置文件加载bean,ApplicationContext和BeanFacotry相比,提供了更多的扩展功能。

不同点:BeanFactory是延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。

6. ApplicationContext通常的实现是什么?

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

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

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

7.Spring AOP 实现原理是什么?

Spring AOP是一种设计思想,称为面向切面编程,利用横切技术剖析对象内部,将业务之间共同调用的逻辑提取并封装为一个可复用的模块,这个模块被命名为切面,该模块减少系统中的重复代码,降低模块间的耦合度,可用于日志,权限认证,事务管理等。

Spring AOP思想的实现一般都是基于代理模式,在Java中采用JDK动态代理模式,但是JDK动态代理模式只能代理接口而不能代理类。因此SpringAOP会在JDK动态代理和CGLIB之间进行切换。

8. 有哪些不同类型的IOC(依赖注入)?

(1)构造器依赖注入(引用方式):构造器依赖注入通过容器触发一个类的构造器来实现 的,该类有一系列参数,每个参数代表一个对其他类的依赖。

(2)Setter 方法注入(传值方式):Setter 方法注入是容器通过调用无参构造器或无参 static 工厂 方法实例化 bean 之后,调用该 bean 的 setter 方法,即实现了基 于 setter 的依赖注入。

9. 解释自动装配的各种模式?

(1)no:这是Spring的默认设置,在该设置下自动装配是关闭的,开发者需要自行在Bean定义中用标签明确地设置依赖关系。

(2)byName:该模式可以根据Bean名称设置依赖关系。当向一个Bean中自动装配一个属性时,容器将根据Bean的名称自动在配置文件中查询一个匹配的Bean。如果找到就装配这个属性,如果没找到就报错。

(3)byType:该模式可以根据Bean类型设置依赖关系。当向一个Bean中自动装配一个属性时,容器将根据Bean的类型自动在配置文件中查询一个匹配的Bean。如果找到就装配这个属性,如果没找到就报错。

(4)constructor:和byType模式类似,但是仅适用于有与构造器相同参数类型的Bean,如果在容器中没有找到与构造器参数类型一致的Bean,那么将会抛出异常。

(5)autodetect:该模式自动探测使用constructor自动装配或者byType自动装配。首先会尝试找合适的带参数的构造器,如果找到就是用构造器自动装配,如果在Bean内部没有找到相应的构造器或者构造器是无参构造器,容器就会自动选择byType模式。

10. Resource 是如何被查找、加载的?

(1)Resource 接口是 Spring 资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成——每个实现类代表一种资源访问策略。

(2)Spring 为 Resource 接口提供了如下实现类:

UrlResource:访问网络资源的实现类。

ClassPathResource:访问类加载路径里资源的实现类。

FileSystemResource:访问文件系统里资源的实现类。

ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:

InputStreamResource:访问输入流资源的实现类。

ByteArrayResource:访问字节数组资源的实现类。

这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。

11.Spring 事务底层原理是什么?

事务都具有以下四个基本特点/属性:

(1)Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败(减款,增款必须一起完成)。

(2)Consistency(一致性):只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态。

(3)Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。

(4)Durability(持久性):事务完成之后,它对于 系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库

原理:

(1)划分处理单元——IoC

由于spring解决的问题是对单个数据库进行局部事务处理的,具体的实现首先用spring中的IoC划分了事务处理单元。并且将对事务的各种配置放到了ioc容器中(设置事务管理器,设置事务的传播特性及隔离机制)。

(2)AOP拦截需要进行事务处理的类

Spring事务处理模块是通过AOP功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用TransactionProxyFactoryBean接口来使用AOP功能,生成proxy代理对象,通过TransactionInterceptor完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取ioc容器事务配置属性,转化为spring事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为TransactionAttribute表示的数据对象。

(3)对事务处理实现(事务的生成、提交、回滚、挂起)

spring委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource数据源支持、hibernate数据源事务处理支持、JDO数据源事务处理支持,JPA、JTA数据源事务处理支持。这些支持都是通过设计PlatformTransactionManager、AbstractPlatforTransaction一系列事务处理的支持。 为常用数据源支持提供了一系列的TransactionManager。

(4)结合

PlatformTransactionManager实现了TransactionInterception接口,让其与TransactionProxyFactoryBean结合起来,形成一个Spring声明式事务处理的设计体系。

12. 什么是事务?

(1)事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。

(2)如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。

(3)当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。

(4)若其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。

13.Spring事务中有哪几种事务传播行为?

spring七个事务传播属性:

(1)PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

(2)PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。

(3)PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。

(4)PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。这是最常见的选择。

(5)PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

(6)PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。

(7)PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

14.Spring事务中的隔离级别有哪几种?

(1)ISOLATION_DEFAULT

这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。

另外四个与JDBC的隔离级别相对应;

(2)ISOLATION_READ_UNCOMMITTED

这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。 这种隔离级别会产生脏读,不可重复读和幻像读。

(3)ISOLATION_READ_COMMITTED

保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

(4)ISOLATION_REPEATABLE_READ

这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。

它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

(5)ISOLATION_SERIALIZABLE

这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。

除了防止脏读,不可重复读外,还避免了幻像读。

关键词:

1)幻读:事务1读取记录时事务2增加了记录并提交,事务1再次读取时可以看到事务2新增的记录;

2)不可重复读取:事务1读取记录时,事务2更新了记录并提交,事务1再次读取时可以看到事务2修改后的记录;

3)脏读:事务1更新了记录,但没有提交,事务2读取了更新后的行,然后事务T1回滚,现在T2读取无效。

脏读:指一个事务读取了一个未提交事务的数据。

不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同.一个事务读取到了另一个事务提交后的数据。

虚读(幻读):在一个事务内读取了别的事务插入的数据,导致前后读取不一致(insert)。

15. Spring 事务实现方式

(1)编程式事务管理:这意味着你可以通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。

(2)声明式事务管理:这种方式意味着你可以将事务管理和业务代码分离。你只需要通过注解或者XML配置管理事务。即分为:

基于XML的声明式事务

基于注解的声明式事务

16. Spring框架的事务管理有哪些优点?

它为不同的事务API(如JTA, JDBC, Hibernate, JPA, 和JDO)提供了统一的编程模型。

它为编程式事务管理提供了一个简单的API而非一系列复杂的事务API(如JTA).

它支持声明式事务管理。

它可以和Spring 的多种数据访问技术很好的融合。

17.Spring事务管理的方式有几种?

(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

(2)基于 TransactionProxyFactoryBean的声明式事务管理

(3)基于 @Transactional 的声明式事务管理

(4)基于Aspectj AOP配置事务

18. 将一个类声明为Springbean的注解有哪些?

一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired注解自动装配的 bean 的类,采用以下注解可实现:

@Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用。

@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。

@Service :对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。

@Controller : 对应 Spring MVC控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

18.Spring中的单例bean的线程安全问题了解吗?

(1)Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。

(2)Spring 的 bean 作用域(scope)类型:

singleton:单例,默认作用域。

prototype:原型,每次创建一个新对象。

request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。

session:会话,同一个会话共享一个实例,不同会话使用不用的实例。

global-session:全局会话,所有会话共享一个实例。

(3)线程安全这个问题,要从单例与原型Bean分别进行说明。

原型Bean:对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。

单例Bean:对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。

如果单例Bean, 是一个无状态Bean:也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。

有状态对象(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

无状态对象(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

(4)对于有状态的bean,Spring官方提供的bean一般提供了通过ThreadLocal去解决线程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。:使用ThreadLocal的好处

使得多线程场景下,多个线程对这个单例Bean的成员变量并不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。这是一种以空间换时间的方式。

当然也可以通过加锁的方法来解决线程安全,这种以时间换空间的场景在高并发场景下显然是不实际的。

19. Spring中的bean的作用域有哪些?

Spring Framework支持五种作用域(其中有三种只能用在基于web的Spring ApplicationContext)。

(1)singleton作用域:

Spring的scope的默认值是singleton

Spring 只会为每一个bean创建一个实例,并保持bean的引用.

(2)prototype作用域:

一个bean定义对应多个对象实例。

每一次请求(将其注入到另一个bean中,或执行getBean()方法)都会产生一个新的bean实例,相当于new操作.

Spring一旦将Bean实例交给(注入)调用者,就不再持有这个bean的引用。就无法再执行bean定义的destroy-method.

清除prototype作用域的bean对象并释放资源,是调用者的职责。

(3)request作用域:

HTTP request表示该针对每一次HTTP请求都会产生一个新的bean,仅适用于WebApplicationContext环境。

(4)session作用域:

HTTP session表示该针对每一次HTTP请求都会产生一个新的bean,仅适用于WebApplicationContext环境。

(5)globalSession作用域:

在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。

20. 谈谈自己对于Spring AOP的理解

AOP(Aspect-OrientedProgramming,面向方面编程),可以说是 OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。

当我们需要为分散的对象引入公共行为的时候,OOP 则显得无能为力。也就是说,OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能,日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。

这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。

而 AOP 技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。

所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

AOP 代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。

而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。

Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

实现 AOP 的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

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

(1)AOP是什么?能做什么?

AOP(Aspect Orient Programming),它是面向对象编程的一种补充,主要应用于处理一些具有横切性质的系统级服务,如日志收集、事务管理、安全检查、缓存、对象池管理等。

AOP实现的关键就在于AOP框架自动创建的AOP代理,AOP代理则可分为静态代理和动态代理两大类,其中静态代理是指使用AOP框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于JDK动态代理、CGLIB等在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强。

面向切面的编程(AOP) 是一种编程范式,旨在通过允许横切关注点的分离,提高模块化。AOP提供切面来将跨越对象关注点模块化。

AOP要实现的是在我们写的代码的基础上进行一定的包装,如在方法执行前、或执行后、或是在执行中出现异常后这些地方进行拦截处理或叫做增强处理

Aop的概念

Pointcut:是一个(组)基于正则表达式的表达式,有点绕,就是说他本身是一个表达式,但是他是基于正则语法的。通常一个pointcut,会选取程序中的某些我们感兴趣的执行点,或者说是程序执行点的集合。

JoinPoint:通过pointcut选取出来的集合中的具体的一个执行点,我们就叫JoinPoint.

Advice:在选取出来的JoinPoint上要执行的操作、逻辑。关于5种类型,我不多说,不懂的同学自己补基础。

Aspect:就是我们关注点的模块化。这个关注点可能会横切多个对象和模块,事务管理是横切关注点的很好的例子。它是一个抽象的概念,从软件的角度来说是指在应用程序不同模块中的某一个领域或方面。又pointcut 和advice组成。

Weaving:把切面应用到目标对象来创建新的 advised 对象的过程。

(2)AspectJ是什么?能做什么?

AspectJ是一个易用的功能强大的AOP框架

AspectJ全称是Eclipse AspectJ, 其官网地址是:http://www.eclipse.org/aspectj/

引用官网描述:

  • a seamless aspect-oriented extension to the Javatm programming language(一种基于Java平台的面向切面编程的语言)
  • Java platform compatible(兼容Java平台,可以无缝扩展)
  • easy to learn and use(易学易用)

可以单独使用,也可以整合到其它框架中。

单独使用AspectJ时需要使用专门的编译器ajc。

java的编译器是javac,AspectJ的编译器是ajc,aj是首字母缩写,c即compiler。

(3)AspectJ和Spring AOP的区别?

相信作为Java开发者我们都很熟悉Spring这个框架,在spring框架中有一个主要的功能就是AOP,提到AOP就往往会想到AspectJ,下面我对AspectJ和Spring AOP作一个简单的比较:

Spring AOP

1、基于动态代理来实现,默认如果使用接口的,用JDK提供的动态代理实现,如果是方法则使用CGLIB实现

2、Spring AOP需要依赖IOC容器来管理,并且只能作用于Spring容器,使用纯Java代码实现

3、在性能上,由于Spring AOP是基于动态代理来实现的,在容器启动时需要生成代理实例,在方法调用上也会增加栈的深度,使得Spring AOP的性能不如AspectJ的那么好

AspectJ

  • AspectJ来自于Eclipse基金会
  • AspectJ属于静态织入,通过修改代码来实现,有如下几个织入的时机:

1、编译期织入(Compile-time weaving): 如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。

2、编译后织入(Post-compile weaving): 也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。

3、类加载后织入(Load-time weaving): 指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar。

  • AspectJ可以做Spring AOP干不了的事情,它是AOP编程的完全解决方案,Spring AOP则致力于解决企业级开发中最普遍的AOP(方法织入)。而不是成为像AspectJ一样的AOP方案
  • 因为AspectJ在实际运行之前就完成了织入,所以说它生成的类是没有额外运行时开销的

(4)对比总结

下表总结了 Spring AOP 和 AspectJ 之间的关键区别:

22. 谈谈自己对于Spring IOC的理解

(1)概念:

控制反转:Spring通过一种称作控制反转IoC的技术促进了松耦合。

当应用了IoC, 一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。

(2)IoC容器:

实现了IoC思想的容器。

功能:实例化,初始化组件,装配组件依赖关系,负责组件生命周期管理。

(3)IoC容器特点:

无需主动new对象,而是描述对象应该如何被创建即可。IoC容器会帮忙创建,即被动实例化。

不需要主动装配对象之间的依赖,而是描述需要哪个服务(组件), IoC容器会帮忙装配(即负责将它们关联在一起),被动接受装配。

IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则。

(4)理解IoC容器的关键问题:

谁控制谁?为什么叫反转?IoC容器控制,而以前是应用程序控制,所以叫反转。

控制什么?控制应用程序所需要的资源(对象,文件...)。

为什么控制?解耦组件之间的关系。

控制的哪些方面被反转了?程序的控制权发生了反转:从应用程序转移到了IoC容器。

23. Spring Boot手动装配有哪几种方式?

(1)使用模式注解 @Component/@Controller/@Component/@Service/@Repository 等

(2)使用配置类 @Configuration 与 @Bean

(3)使用模块装配 @EnableXXX 与 @Import

24. Spring是怎么解决循环依赖的?

(1)回答:循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleA,则它们最终反映为一个环。

(2)Spring如何解决循环依赖?

假设场景如下,A->B->A

1)实例化A,并将未注入属性的A暴露出去,即提前曝光给容器Wrap

2)开始为A注入属性,发现需要B,调用getBean(B)

3)实例化B,并注入属性,发现需要A的时候,从单例缓存中查找,没找到时继而从Wrap中查找,从而完成属性的注入

4)递归完毕之后回到A的实例化过程,A将B注入成功,并注入A的其他属性值,自此即完成了循环依赖的注入

(3)spring中的循环依赖会有3种情况:

1)构造器循环依赖

    构造器的循环依赖是不可以解决的,spring容器将每一个正在创建的bean标识符放在一个当前创建bean池中,在创建的过程一直在里面,如果在创建的过程中发现已经存在这个池里面了,这时就会抛出异常表示循环依赖了。

2)setter循环依赖

   对于setter的循环依赖是通过spring容器提前暴露刚完成构造器注入,但并未完成其他步骤(如setter注入)的bean来完成的,而且只能决定单例作用域的bean循环依赖,通过提前暴露一个单例工厂方法,从而使其他的bean能引用到该bean.当你依赖到了该Bean而单例缓存里面有没有该Bean的时候就会调用该工厂方法生产Bean,

Spring是先将Bean对象实例化之后再设置对象属性的

Spring先是用构造实例化Bean对象,此时Spring会将这个实例化结束的对象放到一个Map中,并且Spring提供了获取这个未设置属性的实例化对象引用的方法。为什么不把Bean暴露出去,而是暴露个Factory呢?因为有些Bean是需要被代理的。

3)prototype范围的依赖

对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为“prototype”作用域的bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

25. Spring由哪些模块组成?

(1)核心容器 SpringCore

提供Spring框架的基本功能。主要组件是BeanFactory, 是工厂模式的实现。BeanFactory使用控制反转IoC模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。                           

(2)Spring上下文

是一个配置文件,向Spring框架提供上下文信息。包括企业服务。                           

(3)Spring AOP

通过配置管理特性,AOP模块直接将面向切面的编程功能,集成到Spring框架中。可以很容易的使Spring框架管理任何支持AOP的对象。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。使用Spring AOP,不用依赖组件,就可以将生命性事务管理继承到应用程序中。      

(4)Spring DAO

JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。                         

(5)Spring ORM

Spring框架插入了若干个ORM框架,从而提供了ORM的对象关系工具。                           

(6)Spring Web模块

Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。              

(7)Spring MVC 框架

MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架便成为高度可配置的,MVC容纳了大量视图技术。

26. 使用Spring框架的好处是什么?

轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。

控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。

面向切面编程(AOP): Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。

容器:Spring包含并管理应用程序对象的配置及生命周期。

MVC框架:Spring的web框架是一个设计优良的web MVC框架,很好的取代了一些web框架。

事务管理:Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。

异常处理:Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。

27. 什么是spring?    

(1)Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。

(2)框架的主要优势之一就是其分层架构,分层架构允许选择使用哪一个组件,同时为了J2EE应用程序开发提供继承的框架。

(3)Spring使用基本的JavaBean来完成以前只能由EJB(EJB是Enterprise Java Beans技术的简称, 又被称为企业Java Beans)完成的事情。

(4)不仅限于服务器端的开发。

(5)Spring的核心是控制反转IoC和面向切面AOP.

(6)Spring是一个分层的JavaSE/EE full-stack一站式轻量级开源框架。
 

猜你喜欢

转载自blog.csdn.net/sulia1234567890/article/details/121071448
今日推荐