Spring IOC AOP

文章详细阐述了Spring框架的核心思想——IOC控制反转和DI依赖注入,包括构造器注入、setter注入、接口注入和注解注入的优缺点。同时,介绍了Spring容器如何管理Bean的生命周期,从加载Bean定义、创建对象到销毁对象的完整过程。此外,文章还讨论了AOP的概念和实现,如切面、通知类型以及SpringAOP的动态代理机制。
摘要由CSDN通过智能技术生成

序言

SpringIOC有两个核心思想就是IOC控制反转和DI依赖注入。IOC 控制反转的基本思想是,将原来的对象控制权从使用者转变成Spring,有了Spring之后可以把整个对象交给spring容器来帮我们进行管理,DI 依赖注入,就是把对应的属性的值注入到具体的对象中。Spring提供标签和@Autowired和@Resource注解等方式注入,注入方式本质上是AbstractAutowireCapableBeanFactory的populateBean() 方法先从BeanDefinition 中取得设置的property值,例如AutowireByName方法会根据bean的名字注入;AutowireByType方法根据Bean的类型注入,完成属性值的注入(涉及Bean初始化过程)。对象会存储在Map结构中,在Spring使用Map结构的SingletonObjects存放完整的Bean对象(涉及三级缓存和循环依赖)。整个Bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(涉及Bean的生命周期)。

一、依赖注入的方式

1、构造器注入

将被依赖对象通过构造函数的参数注入给依赖对象,并在初始化对象的时候注入。
优点:对象初始化完成后便可获得可使用的对象。
缺点:当需要注入的对象很多时,构造器参数列表将会很长。不够灵活。若有多种注入方式,每种方式,只需注入指定几个依赖,那么需要提供多个重载的构造函数,比较麻烦。

2、setter方法注入

IOC Service Provider 通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。
优点:灵活,可以选择性地注入需要的对象。
缺点:依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。

3、接口注入

依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的依赖。
优点:接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
缺点:侵入性太强,不建议使用。

4、字段注入

@Autowired 和 @Resource 都是 Spring 框架中用于依赖注入的注解。它们都可以用于自动装配 bean 对象,但是在使用时有一些不同点:
(1)@Autowired 注解是按照类型自动装配 bean 对象,如果需要注入的 bean 对象存在多个实例,则需要使用 @Qualifier 注解指定具体的 bean 名称。而 @Resource 注解默认按照名称自动装配 bean 对象,也可以通过 name 属性指定具体的 bean 名称。如果使用name属性,则使用ByName的自动注入策略,而使用Type属性时,则使用ByType的自动注入策略。如果既不指定ByName属性也不指定ByType属性,这时将通过反射机制使用ByName自动注入策略。
(2)@Autowired 注解是 Spring 框架提供的注解,而 @Resource 注解是 Java EE 标准中提供的注解。因此,如果需要实现跨平台的依赖注入,推荐使用 @Resource 注解。
(3)@Autowired 注解可以用在构造方法、Setter 方法、字段和方法上,而 @Resource 注解只能用在字段和方法上。
(4)@Autowired 注解是可选的,当设置为@Autowired(required = true),如果找不到对应的 bean 对象,Spring 容器会抛出异常。而 @Resource 注解是强制性的,如果找不到对应的 bean 对象,会抛出 NoSuchBeanDefinitionException 异常。

需要注意的是,在使用 @Autowired 或 @Resource 进行依赖注入时,都需要在配置文件中声明自动扫描的包路径,以便 Spring 容器能够自动扫描并注入相应的 bean 对象。
@Resource装配顺序
~如果同时指定了name和type,则从spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
~如果指定了name,则从上下文中查找名称匹配的bean进行装配,找不到则抛出异常。
~如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或者是找到多个,都会抛出异常。
~如果既没有指定name,也没有指定type,则自动按照ByName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按照ByType自动注入。

二、Spring 容器

Spring 容器是 Spring 框架中的一个核心组件,用于管理和组织应用中的对象(Bean)。它负责创建、初始化、装配和管理应用中的 Bean,使得应用程序能够以一种高效和可维护的方式工作。
在 Spring 容器中,所有的 Bean 都以对象的形式存在,并由 Spring 容器进行管理。当应用程序启动时,Spring 容器会根据配置文件中的信息,自动扫描应用程序中的所有 Bean,将它们实例化、初始化,并进行依赖注入。一旦 Bean 实例化完成,Spring 容器就会将这些 Bean 对象保存在自己的容器中,并可以根据需要提供给应用程序使用。

Spring 容器提供了不同的实现,其中最常用的是 ApplicationContext 接口的实现类。它是 Spring 容器的一种实现,提供了许多附加功能,如国际化、资源加载、事件处理等。同时,Spring 还提供了一些其他的容器,如 WebApplicationContext 用于 Web 应用程序的容器管理,以及 EmbeddedWebApplicationContext 用于嵌入式 Web 应用程序的容器管理等。

三、Bean的生命周期

bean的生命周期,主要分为创建、使用和销毁

1、加载Bean定义

通过 loadBeanDefinitions 扫描所有xml配置、注解将Bean记录在beanDefinitionMap中

2、创建Bean对象

通过 createBean 遍历 beanDefinitionMap 创建bean
(1)构建对象
容器通过 createBeanInstance 进行对象构造,先用反射机制从“Bean定义”中的BeanClass拿到这个类的构造方法;获取构造方法的规则:
~当Bean中只有一个构造方法时,无论该构造方法有没有入参,都会获取到该构造方法。
~当Bean中有多个构造方法时,会先获取带有@Autowired注解的构造方法,当多个构造方法都有@Autowired注解注解时,容器无法识别构造哪个方法,产生报错;当构造方法都没有@Autowired注解,容易会优先获取无参构造方法。
~当多个方法都有入参,则也会报错。

准备参数 根据类查找>参数名查找

构造对象,无参对象直接实例化
注意:不建议在任何Bean中添加多个构造方法。
(2)填充属性
通过populateBean方法为Bean内部所需的属性进行赋值,通常是 @Autowired 注解的变量,通过三级缓存机制进行填充。
(3)初始化Bean对象
通过initializeBean对填充后的实例进行初始化。

填充初始化容器相关信息
1.通过 invokeAwareMethods 方法:为实现aware接口【信息感知接口】的Bean 设置注入beanName、beanFactory等容器信息。

2.初始化构造方法
通过 invokeInitMethods 方法进行初始化:

3.如果Bean实现InitializingBean接口进行处理【未实现则不进行】

afterPropertiesSet方法【bean填充属性后执行】
initMethod 方法
Bean的后置处理
在invokeInitMethods 的前后进行

applyBeanPostProcessorsBeforeInitialization
invokeInitMethods
applyBeanPostProcessorsAfterInitialization
在后置处理中处理了包括:AOP【AnnotationAwareAspectJAutoProxyCreator】

负责 构造后@PostConstruct 和 销毁前@PreDestroy 的 InitDestoryAnnotationBeanPostProcessor 等。

注册销毁
通过reigsterDisposableBean处理实现了DisposableBean接口的Bean的注册。

3、添加到单例池

通过 addSingleton 方法,将Bean 加入到单例池 singleObjects

4、销毁

(1)销毁前
调用 bean中@PreDestory 注解的方法

通过 postProcessBeforeDestruction 方法调用destoryBean逐一销毁Bean

(2)销毁
调用 destoryBeans

(3)执行客户自定义销毁
调用 invokeCustomDestoryMethod

四、AOP

AOP(Aspect-OrientedProgramming,面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)进行封装起来,便于减少系统重复的代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。

AOP 当中的概念

切面 (Aspect)可以理解成,就是一个特殊的类(包含的都是增强核心业务的代码),切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!

连接点(join point)通俗理解就是整个系统的所有方法都可以称为连接点

切入点(Pointcut) 就是被选中的连接点,可以通过execution来确定选中的连接点有哪些

通知(Advice)在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能),就是切面这个类中的代码块

织入(Weaving) 把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)

Spring Aop中的通知类型:

前置通知(Before Advice): 在目标方法被调用前调用通知功能;相关的类org.springframework.aop.MethodBeforeAdvice

后置通知(After Advice): 在目标方法被调用之后调用通知功能;相关的类org.springframework.aop.AfterReturningAdvice

返回通知(After-returning): 在目标方法成功执行之后调用通知功能;

异常通知(After-throwing): 在目标方法抛出异常之后调用通知功能;相关的类org.springframework.aop.ThrowsAdvice

环绕通知(Around): 把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能相关的类org.aopalliance.intercept.MethodInterceptor

spring Aop实现的基础

spring aop实现是通过动态代理的方式实现的,动态代理避免了静态代理需要定义冗余的代理类,实现类,动态代理分为两种,第一种就是jdk 动态代理,第二种就是cglib 动态代理,aop 实现同时采用两种代理模式。

两种动态代理的区别:

jdk动态代理模式 :采用反射的方式,只能对实现接口的类生成代理,具有加载速度快,执行效率低的特点。

cglib动态代理模式:采用的asm,通过字节码形式实现,是针对类实现代理,具有加载速度慢,执行效率高的特点。

基于AspectJ实现基础上需要连接的几个内置注解

execution函数用于匹配方法执行的连接点,语法为:

execution(方法修饰符(可选) 返回类型 方法名(参数) 异常模式(可选))

参数部分允许使用通配符:

匹配任意字符,但只能匹配一个元素

匹配任意字符,可以匹配任意多个元素(零到若干个都可以),必须和*联合使用

“execution(public * com.qli.controller.TestController.*(…))”
@Pointcut(value = “@annotation(com.qli.config.RequestLog)”)任何方法使用RequestLog注解都会触发该切面,进入切点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值