前言
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
IOC
1.IOC的概念
控制反转(IoC=Inversion of Control)IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓"控制反转"的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
IoC还有一个另外的名字:"依赖注入 (DI=Dependency Injection)" ,即由容器动态的将某种依赖关系注入到组件之中
案例:实现Spring的IoC
IOC/DI
将以前由程序员实例化对象/赋值的工作交给了spring处理
2.IOC的运用
Spring IoC容器常用的实现是ApplicationContext,它是一个具有丰富功能的IoC容器。通过在配置文件中定义Bean的信息,或使用注解方式进行配置,应用程序可以借助ApplicationContext来获取所需的Bean实例,并利用容器提供的功能,如AOP(面向切面编程)、事务管理等。
3.IOC的特点
Spring IoC通过将对象的创建、组装和管理任务交给容器来完成,实现了对象之间的解耦和灵活性。它简化了应用程序的开发和维护,提高了代码的可复用性和可测试性。同时,Spring IoC还提供了丰富的功能和扩展点,使得开发者可以更加方便地进行企业级应用程序的开发。
4.IOC的底层逻辑
IoC 底层通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下。
- 在配置文件(例如 Bean.xml)中,对各个对象以及它们之间的依赖关系进行配置;
- 我们可以把 IoC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;
- 容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;
- IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。
5.IOC的注入方式
a.set注入 property name value ref
基本数据注入
String
自定义类型注入(开放中常用)
b.构造注入 construct-arg
c.自动装配
byName 根据当前Bean对象中属性名去spring上下文
byType 根据接口自动在spring的上下文去找实现类
AOP
1.AOP的概念
Spring AOP(Aspect-oriented Programming,面向切面编程)是Spring框架提供的一个重要特性,用于实现横切关注点的模块化和可重用性。它通过在不修改原有业务逻辑代码的情况下,将横切关注点与核心业务逻辑进行解耦,并通过切面(Aspect)来定义和管理这些关注点。
在传统的面向对象编程中,业务逻辑代码通常分散在各个对象中,而横切关注点(如日志记录、事务管理、安全控制等)则相互交织其中,导致代码的重复和难以维护。而Spring AOP则将横切关注点作为一个独立的模块,称为切面(Aspect),并通过一种称为切入点(Pointcut)的机制来选择在哪些连接点(Joinpoint)上应用切面。
AOP------ 即面向切面编程
2.AOP的核心
Spring AOP的核心概念包括以下几个:
目标(Target):被通知(被代理)的对象
连接点(Joinpoint):连接点是程序执行过程中可以插入切面的点。例如方法的调用、方法的执行、字段的访问等。
通知(Advice):通知定义了切面在连接点上执行的行为。包括前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),
切入点(Pointcut):切入点是通过表达式或注解来选择在哪些连接点上应用切面。连接点可以是方法的执行、方法的调用、字段的访问等。
适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)
切面(Aspect):切面是横切关注点的模块化和可重用单元。它由切入点、通知和其他配置元素组成。切面定义了应该在哪些连接点上执行特定的行为。
Spring AOP可以与Spring IoC容器无缝集成,通过配置文件或注解方式将切面定义为Bean,并由容器负责管理和应用。Spring AOP的实现基于动态代理技术,可以使用JDK动态代理或CGLIB字节码生成库来创建代理对象。
3.AOP的代理
工具类org.springframework.aop.framework.ProxyFactoryBean用于创建代理对象,并且在一般情况下需要注入以下三个属性:
-
proxyInterfaces:代理应该实现的接口列表(List)。这个属性指定了代理对象应该实现的接口列表,通过实现这些接口,代理对象可以对外提供与目标对象相同的接口方法。
-
interceptorNames:需要应用到目标对象上的通知Bean的名字(List)。这个属性指定了应该应用到目标对象上的通知Bean的名字列表。通知Bean是实现切面逻辑的对象,它定义了在目标对象的特定连接点上执行的操作。
-
target:目标对象(Object)。这个属性指定了被代理的目标对象,即需要被代理的实际业务对象。
通过设置以上三个属性,ProxyFactoryBean可以根据配置创建一个代理对象,该代理对象可以拥有与目标对象相同的接口,并在方法调用前后应用通知逻辑。
java
<bean id="targetObject" class="com.example.TargetObject" />
<bean id="adviceBean" class="com.example.AdviceBean" />
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.example.TargetInterface</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>adviceBean</value>
</list>
</property>
<property name="target" ref="targetObject" />
</bean>
ProxyFactoryBean创建了一个代理对象,该代理对象实现了com.example.TargetInterface接口,并应用了名为adviceBean的通知Bean。被代理的目标对象是targetObject。
通过配置ProxyFactoryBean,我们可以将切面逻辑(adviceBean)与目标对象(targetObject)进行解耦,并最终得到一个代理对象,该代理对象可以在目标对象的方法调用前后执行通知逻辑。
ProxyFactoryBean提供了一种简单而灵活的方式来实现AOP和动态代理,可以帮助我们在应用程序中实现横切关注点的分离,并增加代码的可维护性和重用性。
4.AOP的通知类型
前置通知:在连接点之前执行的通知()
实现org.springframework.aop.MethodBeforeAdvice接口
买书、评论前加系统日志
后置通知:在连接点正常完成后执行的通知
实现org.springframework.aop.AfterReturningAdvice接口
买书返利(存在bug)
环绕通知:包围一个连接点的通知,最大特点是可以修改返回值,由于它在方法前后都加入了自己的逻辑代码,因此功能异常强大。
org.aopalliance.intercept.MethodInterceptor
类似拦截器,会包括切入点,目标类前后都会执行代码。
异常通知:这个通知会在方法抛出异常退出时执行
org.springframework.aop.ThrowsAdvice
出现异常执行系统提示,然后进行处理。价格异常为例
过滤通知(适配器):适配器=通知(Advice)+切入点(Pointcut)
org.springframework.aop.support.RegexpMethodPointcutAdvisor
处理买书返利的bug
面试题
1**、Spring的IOC和AOP机制?**
我们是在使用 Spring 框架的过程中,其实就是为了使用 IOC ,依赖注入,和 AOP ,面向切面编程,这两
个是 Spring 的灵魂。 主要用到的设计模式有工厂模式和代理模式。
IOC 就是典型的工厂模式,通过 sessionfactory 去注入实例。
AOP 就是典型的代理模式的体现。
代理模式是常用的 java 设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类
预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在
关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通
过调用委托类的对象的相关方法,来提供特定的服务。
spring 的 IoC 容器是 spring 的核心, spring AOP 是 spring 框架的重要组成部分。
在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来创建被调用者的实例。但在
spring 里创建被调用者的工作不再由调用者来完成,因此控制反转( IoC );创建被调用者实例的工作通
常由 spring 容器来完成,然后注入调用者,因此也被称为依赖注入( DI ),依赖注入和控制反转是同一
个概念。
面向方面编程( AOP) 是以另一个角度来考虑程序结构,通过分析程序结构的关注点来完善面向对象编程
( OOP )。 OOP 将应用程序分解成各个层次的对象,而 AOP 将程序分解成多个切面。 spring AOP 只实
现了方法级别的连接点,在 J2EE 应用中, AOP 拦截到方法级别的操作就已经足够。在 spring 中,未来使
IoC 方便地使用健壮、灵活的企业服务,需要利用 spring AOP 实现为 IoC 和企业服务之间建立联系。
IOC: 控制反转也叫依赖注入。利用了工厂模式
将对象交给容器管理,你只需要在 spring 配置文件总配置相应的 bean ,以及设置相关的属性,让
spring 容器来生成类的实例对象以及管理对象。在 spring 容器启动的时候, spring 会把你在配置文件
中配置的 bean 都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些 bean 分配给你需要
调用这些 bean 的类(假设这个类名是 A ),分配的方法就是调用 A 的 setter 方法来注入,而不需要你在
A 里面 new 这些 bean 了。
注意:面试的时候,如果有条件,画图,这样更加显得你懂了 .
spring ioc 初始化流程
AOP: 面向切面编程。( Aspect-Oriented Programming )
AOP 可以说是对 OOP 的补充和完善。 OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,
用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候, OOP 则显得无能为力。
也就是说, OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代
码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在 OOP 设计中,它
导致了大量代码的重复,而不利于各个模块的重用。
将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体
业务逻辑)中去。
实现 AOP 的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装
饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建 " 方面 " ,从而使得编
译器可以在编译期间织入有关 " 方面 " 的代码 .
简单点解释,比方说你想在你的 biz 层所有类中都加上一个打印 ' 你好 ' 的功能 , 这时就可以用 aop 思想来做 .
你先写个类写个类方法,方法经实现打印 ' 你好 ', 然后 Ioc 这个类 ref = "biz.*" 让每个类都注入即可实现。
2**、依赖注入的方式有几种,各是什么****?**
一、构造器注入
将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。
优点:
对象初始化完成后便可获得可使用的对象。
缺点:
当需要注入的对象很多时,构造器参数列表将会很长;
不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函
数,麻烦。
二、 setter 方法注入
IoC Service Provider 通过调用成员变量提供的 setter 函数将被依赖对象注入给依赖类。
优点:
灵活。可以选择性地注入需要的对象。
缺点:
依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
三、接口注入
依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参
数就是要注入的对象。
优点
接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
缺点:
侵入行太强,不建议使用。
PS :什么是侵入行?
如果类 A 要使用别人提供的一个功能,若为了使用这功能,需要在自己的类中增加额外的代码,这就是
侵入性。