http://item.congci.com/item/mianxiang-qiemian-biancheng-aop-zuoyong
在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
1、面向切面编程(AOP)
面向切面编程(AOP)就是对软件系统不同关注点的分离,开发者通过拦截方法调用并在方法调用前后添加辅助代码。
AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多了类的公共行为封装到一个可重用的模块,并将其命名为“Aspect”,即切面。
所谓“切面”,简单地说,就是将那些于业务无关,却为月舞模块所共同调用的逻辑或责任封装起来。
切面就是横切面,代表的是一个普遍存在的共有功能。
AOP代表的是一个横向关系
AOP吧软件系统分为两个部分:核心关注点和横切关注点。
业务出路的主要流程是核心关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
2、AOP的作用在与分离系统中各个关注点,将核心关注点和横切关注点分离开来。
java代码:
public class BusinessLogic{
public voidSomeOPration(){
//日志记录;
//权限验证;
DoSomething();
//失误控制;
}
}
3、AOP技术的实现
AOP技术是建立在JAVA语言的反射机制与动态代理机制之上的。
业务逻辑组件在运行过程中,AOP容器动态创建一个代理对象供使用者调用。该代理对象已经按程序员的意图将切面成功切入到目标方法的连接点上,从而切面的功能与业务逻辑的功能同时的以执行。
AOP是一种编程概念,因此他并未绑定带任何特定的语言。事实上,他对所有单独的、垂直的分解式(AOP通常被认为是横向分解)的语言(不仅是OO语言)都有帮助。AOP在不同语言都有实现(如C++,Smalltalk,C#,C,Java)。
4、拦截器的设计原理
Struts2.0的拦截器的设计体现了一种编程的设计理念,即面向切面编程AOP。
拦截是AOP的一种实现策略,在AOP中某个方法或字段被访问,可以进行拦截,然后在其之前或其之后加入某些操作。
5、什么是拦截器(Interceptor)?
拦截器是动态拦截Action调用的对象。他提供了中机制是开发者可以在一个Action执行之前或执行之后插入需要的代码。
6、理解DRY(Don't Repeat Yourself)规则
在软件开发领域,有一个非常重要的规则:Don't Repeat Yourself,就是所谓的DRY规则,意思就是不要写重复代码。
为什么要使用方法调用呢?而不是在三个地方使用重复的代码呢?
很多初学者认为是为了编程的简单,代码简洁。实际上,这是次要的,最重要的原因是为了软件后期的升级及维护。
7、拦截器的意义
拦截器是对调用方法的改进。我们说某个实例是一个拦截器时,这是从行为上来说的,如果从代码的角度来看,拦截器也是一个类,类中包含有方法,知识这个方法比较特殊,他会在目标方法调用之前“自动”执行。
进一步改进,如图:
作用:(1)提供可更高层次的解耦
(2)允许改变被调用方法的方法体
(3)可以改变调用的目标方法
8、实现原理
如何自动的调用拦截器,而且知道到底调用呢个拦截器的方法?大部分的时候,拦截器方法都是通过JDK的动态代理来调用的,AOP的实现机制。
9、拦截器在Struts2.0中的角色
作用:(1)拦截器是通过struts.xml文件配置的,从而实现了对Action通用操作的可插拨式管理。
(2)降低了Action与特定代码的耦合性
(3)提高了ACtion的复用性
(4)吧多个Action中需要重复指定的代码取出,放在拦截器类中定义,从而提供更好地代码重用。
10、Struts2中的拦截器
在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timer、params等。
如果在struts.xml中配置<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:
<package name="xxx" extends="struts-default" > ... </package>
11、拦截器的定义
在struts.xml文件中定义拦截器语法格式:
<interceptor name="拦截器名" class=“拦截器实现类/”>
12、应用定义好的拦截器
<interceptor-ref name="拦截器名/">
在struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。
<default-interceptor-ref name="defaultStack/">
上面在defaultStack中引用的拦截器都可以<action>中不经过引用可以使用
注意:如果在<action>中引用了任何拦截器后,要使用在defaultStack中定义的拦截器,需要在<action>中重新引用。
13、params拦截器使用
当客户端的一个form想服务器端提交请求时,如有textfield,代码如下:
<s:form action="login" >
username <s:textfield name="username"/> <br>
password <s:password name="password" /> <br>
<s:submit/>
</s:form>
在提交后,Struts2将会自动调用login动作类中的setXX方法,并将文本框中的值通过setXXX方法的参数传入。
实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interception.Parameterslnterceptor.
由于params已经在defaultStack中定义,因此,在未引用拦截器的<action>中是会自动引用params的。
如下面的配置代码,在访问login动作时,Struts是会自动执行相应的setter方法的。
<action name="login" class=“com.ascent.action.LoginAction"> <result>/success.jsp</result>
<result name="input">/login.jsp</result>
</action>
这样,登陆表单中的用户名,密码参数就会在Action类中被set进去,完成登陆功能。
但如果在<action>中引用了其他拦截器,就必须显示的引用params拦截器,Struts2不能调用相应的setter方法来初始化参数。如下面的配置代码所示:
<action name="login" class=“com.ascent.action.LoginAction">
<interceptor-ref name="timer" />
<interceptor-ref name="logger"/>
<interceptor-ref name="params"/>
<result>/success.jsp</result>
<result name="input">/login.jsp</result>
</action>
我们可以不去配置params拦截器,配置timer和logger或任意一个,测试参数username、password的值,应该是没有得到表单提交的值,因为params拦截器已经不起作用了。
14、使用拦截器栈
为了能在多个动作中方便的引用同一个或几个拦截器,可以使用拦截器栈将这些拦截器当个整体来引用。
拦截器栈要在<package>标签中使用<interceptors>和子标签<interceptor-stack>来定可以像使用拦截器一样使用拦截器栈。
<package name="demo" extends="struts-default" >
<interceptors>
<interceptor-stack name="mystack">
<interceptor-ref name="timer" />
<interceptor-ref name="logger" />
<interceptor-ref name="params" />
</interceptor-stack>
</interceptors>
<action name="login" class="com.ascent.action.LoginAction">
<interceptor-ref name="mystack"/>
</action>
</package>