当前位置: 首页 > news >正文

详解IOC、AOP及常见面试问题

IoC(Inversion of Control, 控制反转)

1.概念

控制反转: 是一种设计原则,指将对象的创建与依赖管理的控制权从应用程序代码中转移到容器(例如Spring容器)。传统的对象创建模式是应用程序手动创建和管理依赖对象,而在IoC中,这些操作被反转,由容器负责。
依赖注入(DI, Dependency Injection): 是IoC的一种具体实现方式,它通过注入依赖对象来解除对象之间的紧耦合关系。

2.IOC的实现方式

Spring框架主要通过依赖注入来实现IoC,有三种常见的依赖注入方式:
构造函数注入:
在对象实例化时通过构造函数传递依赖对象。构造函数注入确保对象在创建时完全初始化,是一种强制依赖关系的注入方式。
配置方式:
XML配置:通过<constructor-arg>标签。
注解配置:通过@Autowired注解在构造函数上标注。

@Component
public class ServiceA {private final ServiceB serviceB;@Autowiredpublic ServiceA(ServiceB serviceB) {this.serviceB = serviceB;}
}

Setter方法注入
在对象创建后通过Setter方法注入依赖。这种方式适用于可选的或延迟初始化的依赖。
配置方式:
XML配置:通过标签。
注解配置:通过@Autowired注解在Setter方法上标注。

@Component
public class ServiceA {private ServiceB serviceB;@Autowiredpublic void setServiceB(ServiceB serviceB) {this.serviceB = serviceB;}
}

字段注入
直接在字段上注入依赖对象,这是最简单的注入方式,但通常不推荐使用,因为它隐藏了依赖关系,降低了代码的可测试性。
配置方式:
通过@Autowired注解直接在字段上标注。

@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}

3.IOC容器

BeanFactory
Spring最基本的IoC容器,负责管理Bean的创建、配置和生命周期。它使用惰性加载(lazy loading)策略,在实际需要Bean时才创建Bean实例。
适用于资源受限的环境。

ApplicationContext
BeanFactory的扩展,提供了更多的功能,比如国家化支持、事件传播、AOP集成等。
常用实现包括ClassPathXmlApplicationContextFileSystemXmlApplicationContextAnnotationConfigApplicationContext等。
默认采用预加载(eager loading)策略,即在容器启动时就实例化所有的单例Bean。

4.IOC的优势

松耦合: IoC通过依赖注入消除了对象之间的紧耦合关系,使代码更加模块化和可维护。
可测试性: 由于依赖可以轻松替换为模拟对象,IoC使单元测试更加简单。
易扩展性: 通过配置文件或注解,IoC容器允许应用程序在不修改代码的情况下进行扩展和修改。

AOP(Aspect-Oriented Programming, 面向切面编程)

1.概念

面向切面编程: AOP是用于分离横切关注点(如日志记录、事务管理、安全性等)的编程范式。这些关注点通常是分散在各个模块中的,在AOP中,这些分散的逻辑被提取出来,通过“切面”(Aspect)统一管理,从而提高代码的模块化程度。

2.AOP的核心概念

切面(Aspect)
切面是AOP的核心模块,它封装了横切关注点的具体实现。一个切面可以包含多个切入点和通知。
切面通常使用@Aspect注解来定义。
连接点(Join Point):
连接点是程序执行过程中可以插入切面逻辑的具体位置。例如,方法的调用、异常的抛出等都可以作为连接点。
在Spring AOP中,连接点主要指方法的执行。
切入点(Pointcut):
切入点定义了切面应该应用在哪些连接点上。可以通过表达式或注解来指定切入点。
常用的切入点表达式有:
execution(* com.example.service.*.*(..)):匹配某个包中所有类的所有方法。
within(com.example.service..*):匹配某个包及其子包中的所有方法。
通知(Advice):
通知是切面在特定的连接点上执行的动作。根据执行的时间点,通知可以分为以下几类:
前置通知(Before): 在方法执行之前执行。
后置通知(After): 在方法执行之后执行。
返回通知(AfterReturning): 在方法成功返回后执行。
异常通知(AfterThrowing): 在方法抛出异常后执行。
环绕通知(Around): 包裹方法的执行,既可以在方法之前,也可以在方法之后执行。环绕通知是最强大的通知类型。

@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBeforeMethod(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {System.out.println("After method: " + joinPoint.getSignature().getName() + ", result: " + result);}@Around("execution(* com.example.service.*.*(..))")public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before method: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed();  // 执行目标方法System.out.println("After method: " + joinPoint.getSignature().getName());return result;}
}

3.AOP的实现方式

Spring AOP的实现有两种主要方式:
基于代理(Proxy-based AOP):
Spring AOP默认通过JDK动态代理或CGLIB代理来实现切面功能。
如果目标对象实现了接口,Spring AOP会使用JDK动态代理;如果目标对象没有实现接口,则使用CGLIB代理。
代理模式在运行时动态地将切面应用到目标对象上,确保目标对象的原始代码不被修改。
基于AspectJ:
AspectJ是一个功能更强大的AOP框架,它不仅支持Spring AOP的功能,还支持编译时织入和类加载时织入。
在Spring中,可以通过引入AspectJ的库,并配置<aop:aspectj-autoproxy>或使用@EnableAspectJAutoProxy注解来启用AspectJ。

4. AOP的应用场景

日志记录:
通过AOP,可以在不修改业务代码的情况下,统一管理和记录日志。
事务管理:
AOP允许在方法调用的前后统一处理事务提交和回滚。
安全检查:
可以通过AOP统一管理权限检查,确保应用程序的安全性。
性能监控:
AOP可以用于监控方法的执行时间,帮助优化系统性能。

5. AOP的优势

关注点分离: AOP将横切关注点与业务逻辑分离,使代码更加清晰和模块化。
减少重复代码: 横切逻辑集中管理,减少了在业务代码中重复实现的需求。
动态调整: 通过配置和注解,可以动态地改变系统的行为,而无需修改业务代码。

常见IOC的面试问题

1.什么是控制反转(IoC)?它解决了什么问题?

控制反转(Ioc)是面向对象编程中的一种设计原则,它将对象的创建和依赖关系的管理权从应用程序代码转移到框架或容器中。传统的应用程序通常由应用程序代码主动创建对象并管理依赖关系,这导致高耦合性、难以进行单元测试和维护。Ioc通过容器控制对象的创建和依赖注入、使得代码更加松耦合、易于测试和维护。

2.依赖注入(DI)是什么?有哪些实现方式?

依赖注入(Dependency Injection, DI)是实现控制反转的一种方式,指的是将对象的依赖通过外部传递给对象,而不是由对象自己创建这些依赖。Spring中常见的依赖注入方式有:
**构造函数注入:**通过构造函数传递依赖对象,强制依赖关系。
**Setter方法注入:**通过Setter方法传递依赖,适用于可选依赖或延迟初始化。
**字段注入:**通过@Autowired注解直接在字段上注入依赖,简单但不推荐,因为它隐藏了依赖关系。

3.Spring Ioc容器的基本功能是什么?

Bean的创建和管理: Ioc容器负责创建和管理Bean的生命周期,从实例化、依赖注入到销毁。
依赖注入: 通过自动或手动配置,将对象的依赖注入到Bean中,解除Bean之间的紧耦合关系。
Bean作用域: 管理Bean的作用域,如单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)等。
Bean的生命周期管理: 支持自定义初始化和销毁方法,提供灵活的生命周期管理机制。

4. Spring中常见的Bean作用域有哪些?

Singleton(单例): 每个容器只创建一个Bean实例,默认作用域。
Prototype(原型): 每次请求都会创建一个新的Bean实例。
Request(请求): 每次HTTP请求都会创建一个新的Bean实例,作用于Web应用程序。
Session(会话): 每个HTTP会话创建一个Bean实例,作用于Web应用程序。
Global Session(全局会话): 用于Portlet应用程序,每个全局HTTP会话创建一个Bean实例。

5.你如何在Spring中配置依赖注入?有哪些方式?

XML配置: 通过Spring配置文件使用<bean>标签来定义Bean,并通过<constructor-arg><property>标签注入依赖。
注解配置: 使用注解如@Autowired@Qualifier@Value等,自动注入依赖。需要在配置类中启用注解支持,如@ComponentScan@Configuration
Java配置类: 使用@Bean注解的方法定义Bean,并在方法参数中直接注入依赖对象,或者使用@Configuration@Component结合实现。

AOP常见面试题

1.什么是AOP?AOP和OOP的区别是什么?

面向切面编程(AOP)是一种编程范式,旨在通过分离横切关注点(如日志记录、事务管理、安全性等)来提高代码的模块化程度。AOP允许将这些横切关注点封装在“切面”中,并在程序运行时动态地应用到目标代码中。
OOP(面向对象编程): 通过类和对象封装数据和行为,促进代码的模块化和重用。
AOP: 专注于处理OOP无法很好处理的横切关注点,进一步提高代码的模块化。AOP通常与OOP结合使用,以在不修改核心业务逻辑的情况下添加或增强功能。

2.Spring AOP有哪些通知类型?

前置通知(Before): 在目标方法执行之前运行的代码。
后置通知(After): 在目标方法执行之后运行的代码,无论方法是否成功执行。
返回通知(AfterReturning): 在目标方法成功返回后运行的代码。
异常通知(AfterThrowing): 在目标方法抛出异常时运行的代码。
环绕通知(Around): 包裹目标方法的代码,在目标方法之前和之后都可以执行逻辑。环绕通知是最强大的通知类型。

@Aspect
public class ExampleAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")public void afterReturning(JoinPoint joinPoint, Object result) {System.out.println("After method: " + joinPoint.getSignature().getName() + ", result: " + result);}@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "exception")public void afterThrowing(JoinPoint joinPoint, Throwable exception) {System.out.println("Exception in method: " + joinPoint.getSignature().getName() + ", exception: " + exception);}@Around("execution(* com.example.service.*.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before method: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed();  // 执行目标方法System.out.println("After method: " + joinPoint.getSignature().getName());return result;}
}

3.什么是切入点表达式?你能举个例子说明吗?

切入点表达式定义了切面应该应用到哪些连接点(Join Point)上。Spring AOP使用AspectJ语法来定义切入点表达式。常见的切入点表达式包括:
execution: 匹配方法的执行。

@Before("execution(* com.example.service.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {// 这个切入点表达式匹配 com.example.service 包下所有类的所有方法。
}

within: 匹配指定类型或包中的所有方法。

@Before("within(com.example.service..*)")
public void beforeMethod(JoinPoint joinPoint) {// 这个切入点表达式匹配 com.example.service 包及其子包中的所有方法。
}

this/target: 匹配指定类型的代理对象或目标对象。

@Before("this(com.example.service.ServiceInterface)")
public void beforeMethod(JoinPoint joinPoint) {// 这个切入点表达式匹配实现了 ServiceInterface 接口的所有代理对象的方法调用。
}

4.如何在Spring中启用AOP?有哪些配置方式?

XML配置: 在Spring配置文件中,通过<aop:config><aop:aspect>标签来定义和配置切面。
注解配置: 使用@Aspect注解来定义切面,并在配置类中使用@EnableAspectJAutoProxy注解启用AOP。
Java配置类: 使用@Configuration注解创建配置类,并在类中启用AOP:

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

Spring AOP:
基于代理的实现,默认支持方法级别的切面,不支持字段级别的切面。
适用于Spring管理的Bean,配置简单,集成Spring生态系统。
主要用于简单的AOP需求,性能较好,易于配置。
AspectJ:
通过编译期织入或加载期织入实现,支持更多的切点类型,如字段访问、构造函数执行等。
可以应用于所有Java类,不局限于Spring管理的Bean。
适用于复杂的AOP需求,配置相对复杂,需要AspectJ编译器或加载器的支持。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • SpringBoot 项目 Jar 包加密,防止反编译
  • ZBrush与Blender雕刻功能哪个更好些?
  • 价值、创新、社区与财富效应:Match项目的成功启示
  • Python+Pytest框架,“conftest.py文件编写如何获取token和获取日志“?
  • 美国税收制度及SAP实施
  • 百年病态集论的症结:3000年不识伪≌直线段
  • 添加选择登录ssh终端
  • Python文本数据切分及HTML数据处理
  • vscode中前端项目文件格式化备份
  • 08_React redux
  • 延迟退休,程序员的你准备好了吗?
  • 基于SpringBoot+Vue的养老院管理系统
  • Java多线程编程-基础篇
  • SQLite的入门级项目学习记录(三)
  • 提权——Linux
  • 《Java编程思想》读书笔记-对象导论
  • 【mysql】环境安装、服务启动、密码设置
  • canvas 五子棋游戏
  • FastReport在线报表设计器工作原理
  • github指令
  • Invalidate和postInvalidate的区别
  • JS函数式编程 数组部分风格 ES6版
  • js继承的实现方法
  • js数组之filter
  • markdown编辑器简评
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 官方解决所有 npm 全局安装权限问题
  • 和 || 运算
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 区块链技术特点之去中心化特性
  • 如何学习JavaEE,项目又该如何做?
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 算法-插入排序
  • 正则与JS中的正则
  • HanLP分词命名实体提取详解
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #if等命令的学习
  • (19)夹钳(用于送货)
  • (2)MFC+openGL单文档框架glFrame
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (pytorch进阶之路)扩散概率模型
  • (ZT)薛涌:谈贫说富
  • (编译到47%失败)to be deleted
  • (补)B+树一些思想
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (算法二)滑动窗口
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)Java算法:二分查找
  • (转)shell调试方法