Spring核心 IoC和AOP原理
1、 什么是Spring
Spring是一个轻量的Java开源框架,它简化了应用开发,实现基于POJO的编程模型。它的两大核心是:IoC(控制反转),AOP(面向切面编程)。
2、 IoC控制反转
简单的说就是将创建对象的权利交由IoC。一般来说,使用对象之前必须创建。但IoC允许我们从容器中直接获得并使用一个对象,无需事先创建它们,也不用去关注多个类之间的相互依赖关系。
原理:利用Java的反射机制,根据配置文件,在运行时动态的去创建实例,并管理各个实例之间的依赖关系。
好处:减少代码;组件松耦合;方便测试;资源统一管理,可配置;
2.1 三种注入方式
2.1.1 构造器注入
接受注入的类中定义一个有参数的构造方法,将被依赖的对象通过这个构造函数参数注入。
优点:对象初始化完成后便可使用。
缺点:当需要注入的对象很多时,构造函数参数列表会很长。如果有多种注入方式,可能需要提供多个构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 | public class Car{ private Wheel wheel; //Constructor Injection public Car(Wheel wheel){ this .wheel = wheel; } void run(){ wheel.run(); } } |
2.1.2 setter方法注入
IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。这个最常用。
优点:灵活。可以选择性地注入需要的对象。
缺点:对象无法在构造完成后马上进入就绪状态。依赖对象初始化完成后,由于尚未注入被依赖对象,因此还不能使用。
1 2 3 4 5 6 7 8 9 10 11 12 | public class Car{ private Wheel wheel; private void setWheel(Wheel wheel){ this .wheel = wheel; } public Wheel getWheel(){ return wheel; } } |
2.1.3 接口注入
依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。
优点:接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
缺点:侵入行太强,不建议使用。
1 2 3 4 5 6 7 8 9 10 11 12 | public class Car implemnets CarInterface{ private Wheel wheel; @override void injectWheel(Wheel wheel){ this .wheel = wheel; } public void run(){ wheel.run(); } } |
2.2 IoC 自动装载
下面以XML配置为例,讲解常见的装载模式:
no: 缺省
1 2 3 4 | <!-- no – 缺省情况下,自动配置是通过“ref”属性手动设定 --> < bean id="person" class="org.spring.autowring.Person"> < property name="ability" ref="ability"></ property > </ bean > |
byName:通过属性名自动装载
1 2 3 4 5 | <!-- Auto-Wiring "byName" 按属性名称自动装配 --> < bean id="person" class="org.spring.autowring.Person" autowire="byName"/> < bean id="ability" class="org.spring.autowring.Ability"> < property name="skill" value="Java Programming"></ property > </ bean > |
byType:通过属性的数据类型自动装载
1 2 3 4 5 | <!-- Auto-Wiring "byType" 按属性名称自动装配 --> < bean id="person" class="org.spring.autowring.Person" autowire="byType"/> < bean id="ability" class="org.spring.autowring.Ability"> < property name="skill" value="Java Programming"></ property > </ bean > |
byType需要注意,如果同时存在两个及以上的符合条件的 bean 时,⾃自动装载会抛出异常。
constructor:在构造函数参数的byType方式
1 2 3 4 5 6 7 8 9 10 | <!-- constructor – 在构造函数参数的byType方式。 --> <!-- 构造方法的参数 --> < bean id="person" class="org.spring.autowring.Person"> < constructor-arg > < ref bean="ability"></ ref > </ constructor-arg > </ bean > < bean id="ability" class="org.spring.autowring.Ability"> < property name="skill" value="Java Programming"></ property > </ bean > |
constructor与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect
如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。
3、 AOP面向切面编程
AOP(面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。
AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么AOP就会使用JDK动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。
3.1 JDK动态代理
spring默认使用JDK的动态代理。JDK动态代理涉及Proxy类和InvocationHandler接口。大致步骤为:
1、通过Proxy获得动态代理类
2、通过反射机制获取代理类的构造方法
3、通过构造函数获得代理对象,并将定义的InvocationHandler实例对象传为参数传入
4、通过代理对象调用目标方法
优点:不需要任何依赖,更加松耦合。
缺点:为每一个目标创建接口
3.2 CGLib动态代理
若目标对象没有实现任何接口,spring使用CGLib进行动态代理。CGLib代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
优点:不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类。
缺点:因为没有使用接口,系统耦合性不如JDK动态代理好。无法对final类代理,无法对final、private方法代理。
如何强制使用CGLIB实现AOP?
1、添加CGLIB库,SPRING_HOME/cglib/*.jar
2、在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
篇幅原因,这里就不展示这两种方式的实现代码了,请参照:https://www.cnblogs.com/puyangsky/p/6218925.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端