Appearance
面试题 Spring
说说你对 IoC 的理解?
得分点 控制反转与依赖注入含义
IoC 是控制反转的意思,是一种面向对象编程的设计思想。在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间的耦合度过高,在一个大型的项目中这十分的不利于代码的维护。IoC 则可以解决这种问题,它可以帮我们维护对象与对象之间的依赖关系,并且降低对象之间的耦合度。
说到 IoC 就不得不说 DI,DI 是依赖注入的意思,它是 IoC 实现的实现方式。由于 IoC 这个词汇比较抽象而 DI 比较直观,所以很多时候我们就用 DI 来代替它,在很多时候我们简单地将 IoC 和 DI 划等号,这是一种习惯。实现依赖注入的关键是 IoC 容器,它的本质就是一个工厂。
加分回答 IoC 是 Java EE 企业应用开发中的就偶组件之间复杂关系的利器。
在以 Spring 为代表的轻量级 Java EE 开发风行之前,实际开发中是使用更多的是 EJB 为代表的开发模式。在 EJB 开发模式中,开发人员需要编写 EJB 组件,这种组件需要满足 EJB 规范才能在 EJB 容器中运行,从而完成获取事务,生命周期管理等基本服务,Spring 提供的服务和 EJB 并没有什么区别,只是在具体怎样获取服务的方式上两者的设计有很大不同:
- Spring IoC 提供了一个基本的 JavaBean 容器,通过 IoC 模式管理依赖关系,并通过依赖注入和 AOP 切面增强了为 JavaBean 这样的 POJO 对象服务于事务管理、生命周期管理等基本功能;
- 而对于 EJB,一个简单的 EJB 组件需要编写远程/本地接口、Home 接口和 Bean 的实体类,而且 EJB 运行不能脱离 EJB 容器,查找其他 EJB 组件也需要通过诸如 JNDI 的方式,这就造成了对 EJB 容器和技术规范的依赖。也就是说 Spring 把 EJB 组件还原成了 POJO 对象或者 JavaBean 对象,以此降低了用用开发对于传统 J2EE 技术规范的依赖。
在应用开发中开发人员设计组件时往往需要引用和调用其他组件的服务,这种依赖关系如果固化在组件设计中,会造成依赖关系的僵化和维护难度的增加,这个时候使用 IoC 把资源获取的方向反转,让 IoC 容器主动管理这些依赖关系,将这些依赖关系注入到组件中,这就会让这些依赖关系的适配和管理更加灵活。
对 AOP 的理解?
得分点 AOP 概念、AOP 作用、AOP 的实现方式
AOP 是一种编程思想,是通过预编译方式和运行期动态代理的方式实现不修改源代码的情况下给程序动态统一添加功能的技术。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。 AOP 技术利用一种称为“横切”的技术,剖解开封装对象的内部,将影响多个类的公共行为封装到一个可重用的模块中,并将其命名为切面。
所谓的切面,简单来说就是与业务无关,却为业务模块所共同调用的逻辑,将其封装起来便于减少系统的重复代码,降低模块的耦合度,有利用未来的可操作性和可维护性。 利用 AOP 可以对业务逻辑各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
AOP 可以有多种实现方式,而 Spring AOP 支持如下两种实现方式。
- JDK 动态代理:这是 Java 提供的动态代理技术,可以在运行时创建接口的代理实例。Spring AOP 默认采用这种方式,在接口的代理实例中织入代码。
- CGLib 动态代理:采用底层的字节码技术,在运行时创建子类代理的实例。当目标对象不存在接口时,Spring AOP 就会采用这种方式,在子类实例中织入代码。
加分回答 在应用场景方面,Spring AOP 为 IoC 的使用提供了更多的便利,一方面,应用可以直接使用 AOP 的功能,设计应用的横切关注点,把跨越应用程序多个模块的功能抽象出来,并通过简单的 AOP 的使用,灵活地编制到模块中,比如可以通过 AOP 实现应用程序中的日志功能。另一方面,在 Spring 内部,例如事务处理之类的一些支持模块也是通过 Spring AOP 来实现的。
AOP 不能增强的类:
- Spring AOP 只能对 IoC 容器中的 Bean 进行增强,对于不受容器管理的对象不能增强。
- 由于 CGLib 采用动态创建子类的方式生成代理对象,所以不能对 final 修饰的类进行代理。
@transactional 注解在什么情况下会失效,为什么?
- 检查方法是不是 public 的
- 异常类型是不是 unchecked 异常。如果想 check 异常也想回滚怎么办,注解上面写明异常类型即可。
@Transactional(rollbackFor=Exception.class) - 数据库引擎要支持事务,如果是 MySQL,注意表要使用支持事务的引擎,比如 innodb,如果是 myisam,事务是不起作用的
- 是否开启了对注解的解析
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> - spring 是否扫描到这个包
- 检查是不是同一个类中的方法调用(如 a 方法调用同一个类中的 b 方法)
- 异常是不是被 catch 了