你对Spring的理解?
Spring是一个轻量级的容器框架,最主要的特点就是IOC和AOP。
- IOC:指的是控制反转,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。我们将控制权交由Spring容器统一进行管理,从而实现松耦合。
- AOP:是一个面向切面的编程,对代码某些类似的方面做一个切割,在不改变原有代码情况下进行一个增强功能的操作,一搬使用的就是用jdk或者cglib动态代理方式实现,通常用来做日志,权限控制,事务等,像事务这种的话,一般使用注解的方式,因为比较简单。
什么是IOC?Spring IOC怎么管理Bean之间的依赖关系,怎么避免循环依赖?
- IOC(Inversion of Control,控制反转)是指将对象的创建和管理控制权从应用程序代码转移到容器中,由容器负责对象的创建、初始化和管理。在Spring中,IOC容器负责创建和管理Bean(应用程序中的对象)。
- Spring IOC通过依赖注入(Dependency Injection,DI)来管理Bean之间的依赖关系,主要有以下几种方式:
- 构造函数注入:通过Bean的构造函数注入依赖对象,在配置文件或使用注解时指定构造函数的参数。
- Setter方法注入:通过Bean的Setter方法注入依赖对象,Spring容器在创建Bean后调用Setter方法设置依赖。
- 接口注入:较少使用,Bean实现特定接口,接口中定义设置依赖对象的方法。
避免循环依赖:
- Spring通过三级缓存机制来解决大部分的循环依赖问题。在创建Bean时,先将Bean的早期引用(未完全初始化的Bean)放入一级缓存(
singletonObjects
)中,当需要依赖其他Bean时,从缓存中查找。如果在创建过程中发现循环依赖,对于单例Bean,Spring利用二级缓存(earlySingletonObjects
)存储早期引用,通过三级缓存(singletonFactories
)生成代理对象或提前暴露Bean的引用,来打破循环。 - 对于基于构造函数的循环依赖,Spring无法自动解决,可通过使用
@Lazy
注解实现延迟加载,或者调整设计来避免。
讲讲静态代理模式的优点及其瓶颈?
- 优点
- 职责清晰:代理类和目标类的职责明确,代理类专注于增强功能(如权限校验、日志记录等),目标类专注于核心业务逻辑,使代码结构更清晰,便于维护。
- 扩展性好:如果需要对目标类的功能进行增强,只需修改代理类,无需改动目标类,符合开闭原则。例如,为一个文件读取类添加日志记录功能,通过静态代理,在代理类中记录日志,不影响原文件读取类的代码。
- 保护目标对象:代理类可以控制对目标类的访问,在某些情况下,防止外部直接访问目标类,起到一定的保护作用。
- 瓶颈
- 代理类过多:当有多个目标类需要代理时,需要编写大量的代理类,导致代码量增加,开发和维护成本上升。例如,项目中有10个不同的业务类都需要添加权限校验功能,就需要编写10个对应的代理类。
- 缺乏灵活性:静态代理类在编译时就已经确定了代理的目标类,运行时不能动态改变。如果业务需求发生变化,需要代理其他目标类,就需要重新编写代理类。
对Java接口代理模式的实现原理的理解是什么?
- 目标类和代理类实现同一个接口,这保证了代理类和目标类具有相同的行为定义。例如,定义一个
UserService
接口,包含login
和register
等方法,目标类UserServiceImpl
实现该接口完成具体业务逻辑,代理类UserServiceProxy
也实现该接口。 - 代理类持有目标类的引用,在代理类的方法中,先执行一些增强逻辑(如权限检查、日志记录等),然后通过目标类的引用调用目标类的方法来执行实际业务逻辑,最后还可以执行一些后续增强逻辑(如资源清理等)。例如,在
UserServiceProxy
的login
方法中,先记录用户登录日志,然后调用UserServiceImpl
的login
方法进行登录验证,登录成功后记录登录结果日志。
如何使用Java反射实现动态代理?
Java反射实现动态代理主要通过java.lang.reflect.Proxy
类和InvocationHandler
接口。
谈谈对Cglib类增强动态代理的实现方式?
- Cglib通过继承目标类来创建代理类,代理类是目标类的子类。
- 利用字节码处理框架(如ASM),在运行时动态生成代理类的字节码。
- 在代理类中,重写目标类的方法,在重写的方法中织入增强逻辑(如在方法调用前后添加日志记录、事务管理等代码),然后通过
super
关键字调用目标类的原方法,完成方法的执行。
什么是AOP?AOP的应用场景有哪些?
AOP(Aspect - Oriented Programming,面向切面编程)是一种编程范式,旨在将横切关注点(如日志记录、事务管理、权限控制、缓存管理等)从业务逻辑中分离出来,形成独立的切面(Aspect),然后在运行时将这些切面动态织入到目标对象的方法执行过程中。
应用场景:
- 日志记录:在方法执行前后自动记录日志,便于系统调试和监控。
- 事务管理:为业务方法自动添加事务控制,确保数据一致性和完整性。
- 权限控制:在方法调用前检查用户权限,防止非法访问。
- 性能监控:统计方法的执行时间,分析性能瓶颈。
- 缓存管理:在方法调用前后检查缓存,减少数据库访问。
讲解OOP与AOP的简单对比?
- 关注点不同:OOP(Object - Oriented Programming,面向对象编程)关注的是将业务逻辑封装成对象,通过对象之间的交互来完成业务功能,强调类、对象、继承、封装和多态等概念;AOP关注的是将横切关注点从业务逻辑中分离出来,以切面的形式对多个对象的共同行为进行统一管理。
- 解决的问题不同:OOP主要解决业务逻辑的模块化和可维护性问题;AOP主要解决在OOP中横切关注点的代码重复和分散问题,例如多个业务类都需要日志记录、事务管理等功能,在OOP中会导致这些代码在多个类中重复出现,而AOP可以将这些功能集中在切面中实现。
- 关系:AOP不是对OOP的替代,而是对OOP的补充和完善,两者结合可以更高效地构建复杂的软件系统。
讲解JDK动态代理和CGLIB代理原理以及区别?
- JDK动态代理原理:JDK动态代理基于Java反射机制,要求目标对象必须实现至少一个接口。代理类实现与目标对象相同的接口,在运行时通过
Proxy.newProxyInstance
方法动态生成代理类实例。当调用代理对象的方法时,实际调用的是InvocationHandler
的invoke
方法,在该方法中通过反射调用目标对象的实际方法,并可在前后添加增强逻辑。 - CGLIB代理原理:CGLIB通过继承目标类来创建代理类,使用字节码处理框架(如ASM)在运行时动态生成代理类的字节码。代理类重写目标类的方法,在重写的方法中织入增强逻辑,然后通过
super
关键字调用目标类的原方法。 - 区别
- 代理对象的创建条件:JDK动态代理要求目标对象实现接口;CGLIB代理不需要目标对象实现接口,可以直接代理类。
- 性能:在创建代理对象时,JDK动态代理基于反射,创建速度相对较慢;CGLIB基于字节码生成,创建速度相对较快。在代理对象的方法调用时,JDK动态代理的反射调用开销相对较大,CGLIB的方法调用通过直接调用子类方法,开销较小。不过随着JVM的优化,两者在实际应用中的性能差异并不明显。
- 应用场景:如果目标对象实现了接口,优先使用JDK动态代理;如果目标对象没有实现接口,或者为了避免创建接口带来的额外复杂性,可使用CGLIB代理。
BeanFactory和FactoryBean有什么区别,BeanFactory和ApplicationContext又有什么不同?
- BeanFactory和FactoryBean的区别
- 概念不同:
BeanFactory
是Spring容器的顶层接口,提供了基本的Bean管理和获取功能,是Spring IOC容器的基础;FactoryBean
是一个接口,实现该接口的类用于创建其他Bean,是一个工厂Bean。 - 作用不同:
BeanFactory
用于管理和获取普通Bean实例;FactoryBean
用于创建特定类型的Bean实例,通过FactoryBean
创建的Bean不是FactoryBean
本身,而是其getObject
方法返回的对象。若要获取FactoryBean
本身,需在Bean名称前加&
符号。
- 概念不同:
- BeanFactory和ApplicationContext的区别
- 功能丰富度:
ApplicationContext
继承自BeanFactory
,除具备BeanFactory
的基本功能外,还提供了更多功能,如国际化支持、事件发布机制、资源加载等。 - 初始化方式:
BeanFactory
采用延迟加载,只有在获取Bean时才创建和初始化Bean;ApplicationContext
在启动时会预加载所有单例Bean,可在系统启动时发现配置错误。 - 应用场景:
BeanFactory
适用于资源有限、对性能要求较高且不需要太多扩展功能的场景;ApplicationContext
适用于大多数企业级应用开发,提供更丰富的功能和便捷的开发体验。
- 功能丰富度:
谈谈Spring Bean创建过程中的设计模式?
- 工厂模式:Spring IOC容器是一个大型工厂,负责创建和管理Bean。通过配置信息(如XML配置文件或注解),Spring容器根据不同的Bean定义创建相应的Bean实例,就像工厂按照不同的生产要求制造产品。
- 单例模式:Spring容器默认创建的Bean是单例的,在整个应用中,一个Bean定义只会创建一个实例。Spring通过内部的单例注册表(如
ConcurrentHashMap
)来存储和管理单例Bean,确保在多线程环境下正确创建和获取单例Bean,避免重复创建,节省资源。 - 策略模式:在Bean的创建过程中,针对不同类型的Bean(如普通Bean、FactoryBean等),采用不同的创建策略。普通Bean通过反射调用构造函数创建,FactoryBean通过调用其
getObject
方法创建,体现了策略模式中针对不同情况采用不同算法或策略的思想。 - 观察者模式:
ApplicationContext
中的事件发布机制运用了观察者模式。当Bean创建完成、销毁等事件发生时,ApplicationContext
会发布相应事件,实现了ApplicationListener
接口的监听器会收到通知并进行处理,实现了对象之间的解耦和事件驱动的编程模型。