目录
1、Spring中DI介绍
1.1、基于配置文件形式注入依赖
1.2、基于注解形式注入依赖
2、Spring中AOP技术
2.1、Java程序的执行流
2.2、使用代理模式的Java程序执行流
2.3、Spring AOP的工作原理
2.4、AOP相关术语
DI(Dependency Injection):依赖注入
bean对象中需要依赖一些其他组件或者对象,依赖关系由容器在运行时决定,简单理解DI就是给对象赋初值。
两种方式处理依赖注入:
①:基于配置形式
②:基于注解形式
①、有参构造函数注入依赖,形式如下:
public class User {
private String name;
private UserInfo userInfo;
public User(String name,UserInfo userInfo) {
this.name = name;
this.userInfo = userInfo;
}
配置文件中内容
②、set方法注入依赖
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
}
bean配置:
其他类型数据介绍
public class User {
private String name;
private UserInfo userInfo;
//list类型
private List lists;
//map类型
private Map maps;
//set类型
private Set sets;
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
public void setLists(List lists) {
this.lists = lists;
}
public void setMaps(Map maps) {
this.maps = maps;
}
public void setSets(Set sets) {
this.sets = sets;
}
Java复制代码
张三
李四
set1
set2
@Value() //注入普通类型属性
@Autowired 注入对象类型
@Resource 注入对象类型
都是在属性上添加
@Component
public class User {
@Value("tulun") //针对普通类型的数据
private String name;
@Autowired //注入对象类型
@Resource //注入对象类型
private UserInfo userInfo;
存在问题:
循环依赖的问题:
如果是使用构造函数的方式注入依赖,有可能会无法解决循环依赖的问题
解决问题:
对于会产生循环依赖的问题的这些类可以通过setter方法注入,可以解决循环依赖
AOP(Aspect Oriented Programing)面向切面编程
通过预编译方式或者运行时动态代理方式实现程序功能的统一维护,可以理解为扩展功能而不用修改源代码
程序运行的过程就是方法调用的过程。我们按照方法执行的顺序,将方法调用排成一串,这样就构成了Java程序流。
将上述的线程栈里的方法调用按照执行流排列,会有如下类似的图
基于时间序列,我们可以将方法调用排成一条线。而每个方法调用则可以看成Java执行流中的一个节点。这个节点在AOP的术语中,被称为Join Point,即连接点。一个Java程序的运行的过程,就是若干个连接点连接起来依次执行的过程。
通常面向对象的程序,代码都是按照时间序列纵向展开的,而他们都有一个共性:即都是以方法调用作为基本执行单位展开的。将方法调用当做一个连接点,那么由连接点串起来的程序执行流就是整个程序的执行过程。
AOP(Aspect Oriented Programming)则是从另外一个角度来考虑整个程序的,AOP将每一个方法调用,即连接点作为编程的入口,针对方法调用进行编程。从执行的逻辑上来看,相当于在之前纵向的按照时间轴执行的程序横向切入。相当于将之前的程序横向切割成若干的面,即Aspect.每个面被称为切面。
所以,根据我的理解,AOP本质上是针对方法调用的编程思路。
AOP是针对切面进行的编程的,那么,你需要选择哪些切面(即 连接点Joint Point)作为你的编程对象呢?
因为切面本质上是每一个方法调用,选择切面的过程实际上就是选择方法的过程。那么,被选择的切面(Aspect)在AOP术语里被称为切入点(Point Cut). 切入点实际上也是从所有的连接点(Join point)挑选自己感兴趣的连接点的过程。
第三方
既然AOP是针对方法调用(连接点)的编程, 现在又选取了你自己感兴趣的链接点---切入点(Point Cut)了,那么,AOP能对它做什么类型的编程呢?AOP能做什么呢?
了解这个之前,我们先要知道一个非常重要的问题:既然AOP是对方法调用进行的编程,那么,AOP如何捕获方法调用的呢?弄清楚这个问题,下面我们先来了解一下引入了代理模式的Java程序执行流是什么样子的。
我们假设在我们的Java代码里,都为实例对象通过代理模式创建了代理对象,访问这些实例对象必须要通过代理,那么,加入了proxy对象的Java程序执行流会变得稍微复杂起来。
我们来看下加入了proxy对象后,Java程序执行流的示意图:
由上图可以看出,只要想调用某一个实例对象的方法时,都会经过这个实例对象相对应的代理对象, 即执行的控制权先交给代理对象。
代理模式属于Java代码中经常用到的、也是比较重要的设计模式。代理模式可以为某些对象除了实现本身的功能外,提供一些额外的功能,大致作用如下图所示:
加入了代理模式的Java程序执行流,使得所有的方法调用都经过了代理对象。对于Spring AOP框架而言,它负责控制着整个容器内部的代理对象。当我们调用了某一个实例对象的任何一个非final的public方法时,整个Spring框架都会知晓。
此时的SpringAOP框架在某种程度上扮演着一个上帝的角色:它知道你在这个框架内所做的任何操作,你对每一个实例对象的非final的public方法调用都可以被框架察觉到!
既然Spring代理层可以察觉到你所做的每一次对实例对象的方法调用,那么,Spring就有机会在这个代理的过程中插入Spring的自己的业务代码
已经介绍了AOP编程首先要选择它感兴趣的连接点----即切入点(Point cut),那么,AOP能对切入点做什么样的编程呢?我们先将代理模式下的某个连接点细化,你会看到如下这个示意图所表示的过程:
为了降低我们对Spring的AOP的理解难度,我在这里将代理角色的职能进行了简化,方便大家理解。**(注意:真实的Spring AOP的proxy角色扮演的只能比这复杂的多,这里只是简化,方便大家理解,请不要先入为主)
代理模式的代理角色最起码要考虑三个阶段:
1.在****调用真正对象的方法之前,应该需要做什么?
在调****用真正对象的方法过程中,如果抛出了异常,需要做什么?
3.在调用真正对象的方法后,返回了结果了,需要做什么?
Spring AOP 根据proxy提供的类型名和方法签名,确定了在其感兴趣的切入点内,则返回AfterReturingAdivce处理建议,proxy得到这个处理建议,然后执行建议;
上述的示意图中已经明确表明了Spring AOP应该做什么样的工作:根据proxy提供的特定类的特定方法执行的特定时期阶段给出相应的处理建议。要完成该工作,Spring AOP应该实现:
1.确定自己对什么类的什么方法感兴趣?-----即确定 AOP的切入点(Point Cut),这个可以通过切入点(Point Cut)表达式来完成;
2. 对应的的类的方法的执行特定时期给出什么处理建议?------这个需要Spring AOP提供相应的建议 ,即我们常说的Advice。
连接点(joinpoint):连接点即指那些可以被拦截点,在spring,指的是方法,spring中支持对方法类型的连接点进行增强,这些方法称之为连接点。
切入点(pointcut):切入点指要对那些连接点进行拦截的定义,在类中有很对的方法可以被增强,实际被增强的方法称之为切入点
增强/通知(Advice):增强值的是拦截到的连接点之后要做的事情就是增强。
增强有5种类型:前置增强、后置增强、异常增强、最终增强、环绕增强
前置增强:在连接点前面执行,前置增强不影响连接点的执行
后置增强:在连接点正常执行完成后执行
异常增强:在连接点抛出异常后执行
最终增强:在连接点执行之后,无论连接点执行成功失败都会执行
环绕增强:环绕增强在连接点前后
切面(Aspect):是切入点和增强的结合,把增强应用到切入点的过程