ioc和aop相关资料.docx

上传人:b****9 文档编号:25072362 上传时间:2023-06-04 格式:DOCX 页数:21 大小:327.07KB
下载 相关 举报
ioc和aop相关资料.docx_第1页
第1页 / 共21页
ioc和aop相关资料.docx_第2页
第2页 / 共21页
ioc和aop相关资料.docx_第3页
第3页 / 共21页
ioc和aop相关资料.docx_第4页
第4页 / 共21页
ioc和aop相关资料.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

ioc和aop相关资料.docx

《ioc和aop相关资料.docx》由会员分享,可在线阅读,更多相关《ioc和aop相关资料.docx(21页珍藏版)》请在冰豆网上搜索。

ioc和aop相关资料.docx

ioc和aop相关资料

SpringIOC核心源码学习

(一)

本文主要以springioc容器基本代码骨架为切入点,理解ioc容器的基本代码组件结构,各代码组件细节剖析将放在后面的学习文章里。

关于IOC容器

IoC容器:

最主要是完成了完成对象的创建和依赖的管理注入等等。

先从我们自己设计这样一个视角来考虑:

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。

那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。

这个描述最具体表现就是我们可配置的文件。

对象和对象关系怎么表示?

可以用xml,properties文件等语义化配置文件表示。

描述对象关系的文件存放在哪里?

可能是classpath,filesystem,或者是URL网络资源,servletContext等。

回到正题,有了配置文件,还需要对配置文件解析。

不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一?

在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

如何对不同的配置文件进行解析?

需要对不同的配置文件语法,采用不同的解析器。

基于以上问题,对应过来,刚好是springioc容器抽象的的几个主要接口:

Resource

BeanDefinition

BeanDefinitionReader

BeanFactory

ApplicationContext

以上五个都是接口,都有各式各样的实现,正是这5个接口定义了springioc容器的基本代码组件结构。

而其组件各种实现的组合关系组成了一个运行时的具体容器。

各代码组件详解

1.Resource

是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResource、URLResource,FileSystemResource等。

每一个资源类型都封装了对某一种特定资源的访问策略。

它是spring资源访问策略的一个基础实现,应用在很多场景。

具体可以参考文章:

Spring资源访问剖析和策略模式应用

2.BeanDefinition

用来抽象和描述一个具体bean对象。

是描述一个bean对象的基本数据结构。

3.BeanDefinitionReader

BeanDefinitionReader将外部资源对象描述的bean定义统一转化为统一的内部数据结构BeanDefinition。

对应不同的描述需要有不同的Reader。

如XmlBeanDefinitionReader用来读取xml描述配置的bean对象。

4.BeanFactory

用来定义一个很纯粹的bean容器。

它是一个bean容器的必备结构。

同时和外部应用环境等隔离。

BeanDefinition是它的基本数据结构。

它维护一个BeanDefinitionsMap,并可根据BeanDefinition的描述进行bean的创建和管理。

5.ApplicationContext

从名字来看叫应用上下文,是和应用环境息息相关的。

没错这个就是我们平时开发中经常直接使用打交道的一个类,应用上下文,或者也叫做spring容器。

其实它的基本实现是会持有一个BeanFactory对象,并基于此提供一些包装和功能扩展。

为什么要这么做呢?

因为BeanFactory实现了一个容器基本结构和功能,但是与外部环境隔离。

那么读取配置文件,并将配置文件解析成BeanDefinition,然后注册到BeanFactory的这一个过程的封装自然就需要ApplicationContext。

ApplicationContext和应用环境细细相关,常见实现有ClasspathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext等。

Classpath、xml、FileSystem、Web等词都代表了应用和环境相关的一些意思,从字面上不难理解各自代表的含义。

当然ApplicationContext和BeanFactory的区别远不止于此,有:

1.资源访问功能:

在Resource和ResourceLoader的基础上可以灵活的访问不同的资源。

2.支持不同的信息源。

3.支持应用事件:

继承了接口ApplicationEventPublisher,这样在上下文中为bean之间提供了事件机制。

……

以上5个组件基本代表了ioc容器的一个最基本组成,而组件的组合是放在ApplicationContext的实现这一层来完成。

以ClasspathXmlApplicationContext容器实现为例,其组合关系如下:

ClassPathXmlApplicationContext的refresh()方法负责完成了整个容器的初始化。

为什么叫refresh?

也就是说其实是刷新的意思,该IOC容器里面维护了一个单例的BeanFactory,如果bean的配置有修改,也可以直接调用refresh方法,它将销毁之前的BeanFactory,重新创建一个BeanFactory。

所以叫refresh也是能理解的。

以下是Refresh的基本步骤:

1.把配置xml文件转换成resource。

resource的转换是先通过ResourcePatternResolver来解析可识别格式的配置文件的路径

(如"classpath*:

"等),如果没有指定格式,默认会按照类路径的资源来处理。

2.利用XmlBeanDefinitionReader完成对xml的解析,将xmlResource里定义的bean对象转换成统一的BeanDefinition。

3.将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。

BeanFactory里将会维护一个BeanDefinition的Map。

当getBean的时候就会根据调用BeanFactory,根据bean的BeanDifinition来实例化一个bean。

当然根据bean的lazy-init、protetype等属性设置不同以上过程略有差别。

refresh()代码如下:

Java代码

1publicvoidrefresh()throwsBeansException,IllegalStateException{

2synchronized(this.startupShutdownMonitor){

3//Preparethiscontextforrefreshing.

4prepareRefresh();

5

6//Tellthesubclasstorefreshtheinternalbeanfactory.

7ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();

8

9//Preparethebeanfactoryforuseinthiscontext.

10prepareBeanFactory(beanFactory);

11

12try{

13//Allowspost-processingofthebeanfactoryincontextsubclasses.

14postProcessBeanFactory(beanFactory);

15

16//Invokefactoryprocessorsregisteredasbeansinthecontext.

17invokeBeanFactoryPostProcessors(beanFactory);

18

19//Registerbeanprocessorsthatinterceptbeancreation.

20registerBeanPostProcessors(beanFactory);

21

22//Initializemessagesourceforthiscontext.

23initMessageSource();

24

25//Initializeeventmulticasterforthiscontext.

26initApplicationEventMulticaster();

27

28//Initializeotherspecialbeansinspecificcontextsubclasses.

29onRefresh();

30

31//Checkforlistenerbeansandregisterthem.

32registerListeners();

33

34//Instantiateallremaining(non-lazy-init)singletons.

35finishBeanFactoryInitialization(beanFactory);

36

37//Laststep:

publishcorrespondingevent.

38finishRefresh();

39}

40

41catch(BeansExceptionex){

42//Destroyalreadycreatedsingletonstoavoiddanglingresources.

43beanFactory.destroySingletons();

44

45//Reset'active'flag.

46cancelRefresh(ex);

47

48//Propagateexceptiontocaller.

49throwex;

50}

51}

52}

以上的obtainFreshBeanFactory是很关键的一个方法,里面会调用loadBeanDefinition方法,如下:

Java代码

53protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{

54//CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.

55XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);

56

57//Configurethebeandefinitionreaderwiththiscontext's

58//resourceloadingenvironment.

59beanDefinitionReader.setResourceLoader(this);

60beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));

61

62//Allowasubclasstoprovidecustominitializationofthereader,

63//thenproceedwithactuallyloadingthebeandefinitions.

64initBeanDefinitionReader(beanDefinitionReader);

65loadBeanDefinitions(beanDefinitionReader);

66}

LoadBeanDifinition方法很关键,这里特定于整个IOC容器,实例化了一个XmlBeanDefinitionReader来解析Resource文件。

关于Resource文件如何初始化和xml文件如何解析都在

Java代码

67loadBeanDefinitions(beanDefinitionReader);

里面的层层调用完成,这里不在累述。

小结

Spring的扩展性是毋庸置疑的,学习spring的设计是一个很好的实践理论结合。

主要个人觉得有几点:

1.框架顶层的设计有着很好的抽象,遵循面向接口编程的规范。

Resource、BeanFactory、ApplicationContext都是非常好的接口抽象,非常明确的定义了该组件的一些功能。

2.利用组合模式。

3.个组件的实现里大量使用了模板方法模式,提升了同一组件代码的复用性。

4.各种设计保留了扩展的接口,很多基于spring的框架都可以很容易的介入实现了自己的一些扩展。

5.框架里采用里很多经典的设计模式,如代理、装饰、策略等等。

本文的目标:

从实现的角度来认识SpringAOP框架。

观察的角度:

从外部接口,内部实现,组成部分,执行过程四个方面来认识SpringAOP框架。

本文的风格:

首先列出AOP的基本概念;

其次介绍框架所涉及到的核心组件列表,组件之间的结构关系图;

然后细化结构图中的部分;

接下来是一个简单的sample;

最后是后记部分。

注:

1.本文的源代码基于Spring2.x。

Spring的源代码也处于演变中,但对基础代码的影响并不大。

2.本文是对SpringIoC容器实现的结构分析的姊妹帖。

正文:

SpringAOP框架涉及的基本概念介绍:

关注点(concern):

一个关注点可以是一个特定的问题、概念、或是应用程序的兴趣区间--总而言之,应用程序必须达到的一个目标。

核心关注点(coreconcern):

业务功能模块,如:

存款模块,取款模块,转账模块等,

横切关注点(crosscuttingconcern):

非功能性的、横切性模块,如:

安全性管理,事务管理,性能监控等。

方面(aspect):

一个方面是对一个横切关注点的模块化,它将那些原本散落在各处的、用于实现这个关注点的代码归整到一处。

连接点(joinpoint):

程序执行过程中的一点,如:

字段访问:

读、写实例变量;

方法调用:

对方法(包括构造方法)的调用;

异常抛出:

特定的异常被抛出。

切入点(pointcut):

一组连接点的总称,用于指定某个增强应该在何时被调用。

切入点常用正则表达式或别的通配符语法来描述,有些AOP实现技术还支持切入点的组合。

增强(advice):

在特定连接点执行的动作。

很多AOP框架都以拦截器(interceptor)的形式来表现增强--所谓拦截器是这样的一个

对象:

当连接点被调用时,它会收到一个回调消息。

基本的增强有:

前增强(BeforeAdvice):

在连接点调用之前,首先调用增强;

后增强(AfterAdvice):

在连接点调用之后,再调用增强,在AspectJ中,后增强又分为三种:

AfterReturningAdvice:

在调用成功完成(没有异常抛出)之后。

AfterThrowingAdvice:

在抛出某种特定类型(或其子类型)的异常之后。

AfterAdvice:

在连接点的任何调用之后,不管调用是否抛出异常。

环绕增强(AroundAdvice):

这类增强可以完全控制执行流程。

除了完成本身的工作之外,它还需要负责主动调用连接点,促使真实的操作发生(proceed)--这通常是通过调用某个特定的方法来完成的。

引介(introduction):

为一个现有的Java类或接口添加方法或字段。

这种技术可以用于实现Java中的多继承,或者给现有对象模型附加新的API。

混入继承(mixininheritance):

一个“混入类”封装了一组功能,这组功能可以被"混入"到现有的类当中,并且无须使用传统的继承手段。

在AOP这里,混入是通过引介来实现的。

在Java语言中,可以通过混入来模拟多继承。

织入(weaving):

将方面整合到完整的执行流程(或完整的类,此时被织入的便是引介中)。

拦截器(initerceptor):

很多AOP框架用它来实现字段和方法的拦截(interception)。

随之而来的就是在连接点(如方法拦截)处挂接一条拦截器链(interceptorchain),链条上的每个拦截器通常会调用下一个拦截器。

AOP代理(AOPproxy):

即被增强(advise)的对象引用--也就是说,AOP增强将在其上执行的这样一个对象引用。

目标对象(targetobject):

位于拦截器链末端的对象实例--这个概念只存在于那些使用了拦截机制的框架之中。

注:

上述概念描述引自《ExpertOne-on-OneJ2EEDevelopmentwithoutEJB》中第八章对AOP概念描述部分,更多精彩部分可以参阅本章的完整内容。

上述概念已被SpringAOP框架很好的实现,相关组件:

Advisor组件,

Advice组件,

Pointcut组件,

Advised组件,

AopProxy组件,

AopProxyFactory组件,

图1.

图1是对增强、切入点、方面、AOP代理之间依赖关系的全景图。

增强和切入点组成一个方面,方面信息与目标对象信息被组织到Advised中,AopProxyFactory通过Advised中保存的信息生成AopProxy

对象,调用AopProxy.getProxy()方法即可获得增强后的对象。

这里要着重了解的是不同的增强子类型,不同的切入点子类型,

对于不同的切入点子类型最重要的两种子类型:

静态切入点,动态切入点,

静态切入点:

根据部署阶段的信息选择增强,如“拦截特定类的所有getter方法”;

动态切入点:

根据运行时的信息选择增强,如“如果某方法的返回值为null,则将其纳入某切入点”。

图2.

图2是对图1中Advisor与Pointcut的实现细化,图中类之间的关系直观上有点乱,但细看下关系还是相当清晰的,

以Advisor结尾的是方面类型,以Pointcut结尾的是切入点类型,

Advisor与Pointcut的复用关系分两类:

一类是组合复用,另一类是具体继承复用,

组合复用例子如:

RegexpMethodPointcutAdvisor与AbstractRegexpMethodPointcut之间的关系,

NameMatchMethodPointcutAdvisor与NameMatchMethodPointcut之间的关系,

具体继承复用例子如:

StaticMethodMatcherPointcutAdvisor与StaticMethodMatcherPointcut之间的关系,

DynamicMethodMatcherPointcutAdvisor与DynamicMethodMatcherPointcut之间的关系,

图3.

图3是对图1中生成AopProxy对象的实现细化,

AopProxyFactory通过AdvisedSupport提供的信息生成AopProxy对象,AopProxy对象的生成分两类方式:

一类是动态代理,另一类是字节码增强;

需要注意的是,ProxyFactory与ProxyFactoryBean并不是功能实现的必要部分,主要目的为编程式使用代理提供便利的API。

下面是一个简单的sample:

Java代码

1//目标对象接口.

2publicinterfaceTarget{

3publicStringplay(intarg);

4}

5//目标对象实现.

6publicclassTargetImplimplementsTarget{

7

8publicStringplay(intarg){

9System.out.println("playmethod....");

10return"[Target:

]"+arg;

11}

12}

13//前置增强

14publicclassMyBeforeAdviceimplementsMethodBeforeAdvice{

15publicvoidbefore(Methodmethod,Object[]args,Objecttarget)

16throwsThrowable{

17System.out.println(method.getName());

18System.out.println("beforemethod!

");

19}

20}

21//后置增强

22publicclassMyAfterAdviceimplementsAfterReturningAdvice{

23publicvoidafterReturning(ObjectreturnValue,Methodmethod,

24Object[]args,Objecttarget)throwsThrowable{

25System.out.println(returnValue+":

aftermethod");

26}

27}

28//切入点实现

29publicclassMyPointcutimplementsPointcut{

30

31publicClassFiltergetClassFilter(){

32

33returnnewClassFilter(){

34

35publicbooleanmatches(Classarg0){

36if(arg0==TargetImpl.class){

37returntrue;

38}

39returnfalse;

40}

41

42};

43}

44

45publicMethodMatchergetMethodMatcher(){

46

47returnnewMethodMatcher(){

48

49publicbooleanisRuntime(){

50

51return

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 唐诗宋词

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1