spring中的AOP与IOC

在J2EE的整个发展历程中,如今正是一个很是时刻。从不少方面来讲,J2EE都是一个伟大的成功:它成功地在从前没有标准的地方创建了标准;大大提高了企业级软件的开放程度,而且获得了整个行业和开发者的普遍承认。然而,J2EE在一些方面已经开始捉襟见肘。J2EE应用开发的成本一般很高。J2EE应用项目至少和从前的非J2EE项目同样容易失败——若是不是更容易失败的话。这样的失败率高得让人难以接受。在这样的失败率之下,软件开发几乎变成了碰运气。而在J2EE遭遇失败的场景中,EJB一般都扮演着重要的角色。所以,J2EE社群不断地向着更简单的解决方案、更少使用EJB的方向发展[1]。然而,每一个应用程序都须要一些基础设施,拒绝使用EJB并不意味着拒绝EJB所采用的基础设施解决方案。那么,如何利用现有的框架来提供这些基础设施服务呢,伴随着这个问题的提出,一个轻量级的J2EE解决方案出现了,这就是Spring Frameworkjava

  Spring是为简化企业级系统开发而诞生的,Spring框架为J2EE应用常见的问题提供了简单、有效的解决方案,使用Spring,你能够用简单的POJO(Plain Old Java Object)来实现那些之前只有EJB才能实现的功能。这样不仅是能简化服务器端开发,任何Java系统开发都能从Spring的简单、可测试和松耦合特征中受益。能够简单的说,Spring是一个轻量级的反向控制(IoC)和面向切面编程(AOP)容器框架[3]。Spring IoC,借助于依赖注入设计模式,使得开发者不用理会对象自身的生命周期及其关系,并且可以改善开发者对J2EE模式的使用;Spring AOP,借助于Spring实现的拦截器,开发者可以实现以声明的方式使用企业级服务,好比安全性服务、事务服务等。Spring IoC和 Spring ; AOP组合,一块儿造成了Spring,这样一个有机总体,使得构建轻量级的J2EE架构成为可能,并且事实证实,很是有效。没有Spring IoC的Spring AOP是不完善的,没有Spring AOP的Spring IoC是不健壮的。本文是以Spring架构的成功的实际商务系统项目为背景,阐述了反向控制原理和面向切面的编程技术在Spring框架中的应用,同时抽取适量代码示意具体应用,并和传统开发模式进行对比,展现了Spring framework的简单,高效,可维护等优势。 web

  一、Spring IoC 1.1 反向控制原理 正则表达式

  反向控制是Spring框架的核心。可是,反向控制是什么意思?到底控制的什么方面被反向了呢?2004年美国专家Martin Fowler发表了一篇论文《Inversion of Control Containers and the Dependency Injection pattern》阐述了这个问题,他总结说是得到依赖对象的方式反向了,根据这个启示,他还为反向控制提出了一个更贴切的名字:Dependency Injection(DI 依赖注入)。 spring

  一般,应用代码须要告知容器或框架,让它们找到自身所须要的类,而后再由应用代码建立待使用的对象实例。所以,应用代码在使用实例以前,须要建立对象实例。然而,IoC模式中,建立对象实例的任务交给IoC容器或框架(实现了IoC设计模式的框架也被称为IoC容器),使得应用代码只须要直接使用实例,这就是IoC。相对IoC 而言,“依赖注入”的确更加准确的描述了这种设计理念。所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来讲,即由容器动态的将某种依赖关系注入到组件之中。 编程

  1.2 IoC在Spring中的实现 设计模式

  任何重要的系统都须要至少两个相互合做的类来完成业务逻辑。一般,每一个对象都要本身负责获得它的合做(依赖)对象。你会发现,这样会致使代码耦合度高并且难于测试。使用IoC,对象的依赖都是在对象建立时由负责协调系统中各个对象的外部实体提供的,这样使软件组件松散链接成为可能。下面示意了Spring IoC 应用,步骤以下: 安全

  (1)定义Action接口,并为其定义一个execute方法,以完成目标逻辑。多年前,GoF在《Design Pattern:Elements of Reusable Object-Oriented Software》一书中提出“Programming to an Interface,not an implementation”的原则,这里首先将业务对象抽象成接口,正是为了实施这个原则。 服务器

  (2)类UpperAction实现Action接口,在此类中,定义一个String型的域message,并提供相应的setter和getter方法,实现的execute方法以下: 架构

public String execute (String str) {

 

 return (getMessage () + str).toUpperCase () ; 框架

}

  (3)编写Spring配置文件(bean.XML

<beans>

 

<bean id="TheAction" class="net.chen.spring.qs.UpperAction">

<property name="message">

<value>HeLLo</value>

</property>

</bean>

</beans>

  (4)测试代码

public void testQuickStart () {

 

 ApplicationContext ctx=new

 FileSystemXmlApplicationContext ("bean.xml");

 Action a= (Action) ctx.getBean ("TheAction");

 System.out.println (a. execute ("Rod Johnson"));

}

  上面的测试代码中,咱们根据"bean.xml"建立了一个ApplicationContext实例,并今后实例中获取咱们所需的Action实现,运行测试代码,咱们看到控制台输出:

……

 

HELLO ROD JOHNSON

  仔细观察一下上面的代码,能够看到:

  (1)咱们的组件并不须要实现框架指定的接口,所以能够轻松的将组件从Spring中脱离,甚至不须要任何修改,这在基于EJB框架实现的应用中是不可思议的。

  (2)组件间的依赖关系减小,极大改善了代码的可重用性。Spring的依赖注入机制,能够在运行期为组件配置所需资源,而无需在编写组件代码时就加以指定,从而在至关程度上下降了组件之间的耦合。

  Spring给咱们带来了如此这般的好处,那么,反过来,让咱们试想一下,若是不使用Spring框架,回到咱们传统的编码模式,状况会是怎样呢?

  首先,咱们必须编写一个配置文件读取类,以实现Message属性的可配置化。

  其次,得有一个Factory模式的实现,并结合配置文件的读写完成Action的动态加载。因而,咱们实现了一个ActionFactory来实现这个功能:

public class ActionFactory {

 

 public static Action getAction (String actionName) {Properties pro = new Properties ();

 try {

  pro.load (new FileInputStream ("config.properties"));

  String actionImplName =(String)pro.get(actionName);

  String actionMessage =(String) pro.get (actionName+"_msg");

  Object obj =Class.forName (actionImplName).newInstance ();

  BeanUtils.setProperty(obj,"message",actionMessage);

  return (Action) obj;

 } catch (FileNotFoundException e) {

  ……

 }

}

  配置文件则采用properties文件形式以下所示:

TheAction=net.chen.spring.qs.UpperAction

 

TheAction_msg=HeLLo

  测试代码也做相应修改。如今不论实现的好坏,总之经过上面新增的多行代码,终于实现了相似的功能。若是如今有了一个新的需求,这样这个ActionFactory每次都新建一个类的实例,显然这对系统性能不利,考虑到咱们的两个Action都是线程安全的,修改一下ActionFactory,保持系统中只有一个Action实例供其它线程调用。另外Action对象建立后,须要作一些初始化工做。修改一下ActionFactory,使其在建立Action实例以后,随即就调用Action.init方法执行初始化。Action的处理这样就差很少了。下面咱们来看看另一个Factory

  ……

  每每这些系统开发中最多见的需求,会致使咱们的代码迅速膨胀,而Spring IoC的出现,则大大缓解了这样的窘境。经过以上实例,能够看出,Spring IoC为咱们提供了以下几方面的优点:

  (1)应用组件不须要在运行时寻找其协做者,所以更易于开发和编写应用;

  (2)因为借助于IoC容器管理组件的依赖关系,使得应用的单元测试和集成测试更利于展开;

  (3)一般,在借助于IoC容器关系业务对象的前提下,不多须要使用具体IoC容器提供的API,这使得集成现有的遗留应用成为可能。

  所以,经过使用IoC可以下降组件之间的耦合度,最终,可以提升类的重用性,利于测试,并且更利于整个产品或系统集成和配置。

 

二、Spring AOP

  2.1 面向切面编程基础

  一般,系统由不少组件组成,每一个组件负责一部分功能,然而,这些组件也常常带有一些除了核心功能以外的附带功能 。系统服务如日志、事务管理和安全常常融入到一些其余功能模块中。这些系统服务一般叫作交叉业务,这是由于它们老是分布在系统的不少组件中。经过将这些业务分布在多个组件中,给咱们的代码引入了双重复杂性。

  (1) 实现系统级业务的代码在多个组件中复制。这意味着若是你要改变这些业务逻辑,你就必须到各个模块去修改。就算把这些业务抽象成一个独立模块,其它模块只是调用它的一个方法,可是这个方法调用也仍是分布在不少地方。

  (2) 组件会由于那些与本身核心业务无关的代码变得杂乱。一个向地址录中添加条目的方法应该只关心如何添加地址,而不是关心它是否是安全或支持事务的。

  此时,咱们该怎么办呢?这正是AOP用得着的地方。AOP帮助咱们将这些服务模块化,并把它们声明式地应用在须要它们的地方,使得这些组件更加专一于自身业务,彻底不知道其它涉及到的系统服务。

  这里的概念切面,就是咱们要实现的交叉功能,是应用系统模块化的一个方面或领域。切面的最多见例子就是日志记录。日志记录在系统中处处须要用到,利用继承来重用日志模块是不合适的,这样,就能够建立一个日志记录切面,而且使用AOP在系统中应用。下图展现了切面应用方式

图表 1 应用切面

  其中,通知Advice是切面的实际实现。链接点Joinpoint是应用程序执行过程当中插入切面的地点,这个地点能够是方法调用,异常抛出,甚至能够是要修改的字段,切面代码在这些地方插入到你的应用流程中,添加新的行为。切入点Pointcut定义了Advice应该应用在那些链接点,一般经过指定类名和方法名,或者匹配类名和方法名式样的正则表达式来指定切入点。

  2.2 AOP在Spring中的实现

  基于AOP,业界存在各类各样的AOP实现,好比,JBoss AOP、Spring AOP、ASPectJ、Aspect Werkz等。各自实现的功能也不同。AOP实现的强弱在很大程度上取决于链接点模型。目前,Spring只支持方法级的链接点。这和一些其余AOP框架不同,如AspectJ和JBoss,它们还提供了属性接入点,这样能够防止你建立特别细致的通知,如对更新对象属性值进行拦截。然而,因为Spring关注于提供一个实现J2EE服务的框架,因此方法拦截能够知足大部分要求,并且Spring的观点是属性拦截破坏了封装,让Advice触发在属性值改变而不是方法调用上无疑是破坏了这个概念。

  Spring的AOP框架的关键点以下:

  (1)Spring实现了AOP联盟接口。在Spring AOP中,存在以下几种通知(Advice)类型

  Before通知:在目标方法被调用前调用,涉及接口org.springFramework.aop.MethodBeforeAdvice;

  After通知:在目标方法被调用后调用,涉及接口为org.springframework.aop.AfterReturningAdvice;

  Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.MethodBeforeAdvice;

  Around通知:拦截对目标对象方法调用,涉及接口为org.aopalliance.intercept.MethodInterceptor。

  (2)用Java编写Spring通知,并在Spring的配置文件中,定义在什么地方应用通知的切入点。

  (3)Spring的运行时通知对象。代理Bean只有在第一次被应用系统须要的时候才被建立。若是你使用的是ApplicationContext,代理对象在BeanFactory载入全部Bean的时候被建立。Spring有两种代理建立方式。若是目标对象实现了一个或多个接口暴露的方法,Spring将使用JDK的java.lang.reflect.Proxy类建立代理。这个类让Spring动态产生一个新的类,它实现所需的接口,织入了通知,而且代理对目标对象的全部请求。若是目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类。在建立这个子类的时候,Spring将通知织入,而且将对目标对象的调用委托给这个子类。此时,须要将Spring发行包lib/cglib目录下的JAR文件发布到应用系统中。

  2.3 Spring AOP的优点

  借助于Spring AOP,Spring IoC可以很方便的使用到很是健壮、灵活的企业级服务,是由于Spring AOP可以提供以下几方面的优点:

  (1)容许开发者使用声明式企业服务,好比事务服务、安全性服务;EJB开发者都知道,EJB组件可以使用J2EE容器提供的声明式服务,可是这些服务要借助于EJB容器,而Spring AOP却不须要EJB容器,借助于Spring的事务抽象框架就能够这些服务。

  (2)开发者能够开发知足业务需求的自定义切面;

  (3)开发Spring AOP Advice很方便。由于这些AOP Advice仅是POJO类,借助于Spring提供的ProxyFactoryBean,可以快速的搭建Spring AOP Advice。

  三、结语

  本文详细阐述了Spring背后的IoC原理和AOP技术,以实际成功项目为背景,抽取简短片段,展现了Spring架构J2EE应用系统的原理。Spring IoC借助于依赖注入机制,减轻了组件之间的依赖关系,同时也大大提升了组件的可移植性,组件获得了更多的重用机会。借助于Spring AOP,使得开发者能声明式、基于元数据访问企业级服务,AOP合理补充了OOP技术,Spring AOP合理地补充了Spring IoC容器。Spring IoC与Spring AOP组合,使得Spring成为成功的J2EE架构框架,并能与标准的EJB等标准对抗,EJB再也不是必需品。Spring已经冲入了J2EE的核心,将引领整个J2EE开发、架构的方向。

相关文章
相关标签/搜索