代理模式及其在spring与struts2中的体现

代理模式

代理模式有三个角色组成:

  1.抽象主题角色:声明了真实主题和代理主题的共同接口。

  2.代理主题角色:内部包含对真实主题的引用,并且提供和真实主题角色相同的接口。

  3.真实主题角色:定义真实的对象。

我们先来看传统方式下一个Proxy的实现实例。

假设我们有一个UserDAO接口及其实现类UserDAOImp:

UserDAO.java:


public interface UserDAO {

public void saveUser(User user);

}

UserDAOImp.java:


public class UserDAOImp implements UserDAO{

public void saveUser(User user) {

……

}

}

如果我们希望在UserDAOImp.saveUser方法执行前后追加一些处理过程,如启动/

提交事务,而不影响外部代码的调用逻辑,那么,增加一个Proxy类是个不错的选择:

UserDAOProxy.java


public class UserDAOProxy implements UserDAO {

private UserDAO userDAO;

public UserDAOProxy(UserDAO userDAO) {

this.userDAO = userDAO;

}

public void saveUser(User user) {

UserTransaction tx = null;

try {

tx = (UserTransaction) ( new InitialContext().lookup("java/tx") );

userDAO.saveUser(user);

tx.commit();

} catch (Exception ex) {

if (null!=tx){

try {

tx.rollback();

}catch(Exception e) {

}

}

}

}

}

UserDAOProxy同样是UserDAO接口的实现,对于调用者而言,saveUser方法的使

用完全相同,不同的是内部实现机制已经发生了一些变化――我们在UserDAOProxy中为

UserDAO.saveUser方法套上了一个JTA事务管理的外壳。

上面是静态Proxy模式的一个典型实现。

现在假设系统中有20个类似的接口,针对每个接口实现一个Proxy,实在是个繁琐无

味的苦力工程。

动态代理

Dynamic Proxy的出现,为这个问题提供了一个更加聪明的解决方案。

我们来看看怎样通过Dynamic Proxy解决上面的问题:


public class TxHandler implements InvocationHandler {

private Object originalObject;

public Object bind(Object obj) {

this.originalObject = obj;

return Proxy.newProxyInstance(

obj.getClass().getClassLoader(),

obj.getClass().getInterfaces(), this);

}

public Object invoke(Object proxy, Method  method, Object[] args)

throws Throwable {

Object result = null;

if (!method.getName().startsWith("save")) {

UserTransaction tx = null;

try {

tx = (UserTransaction) ( new InitialContext().lookup("java/tx") );

result = method.invoke(originalObject, args);

tx.commit();

} catch (Exception ex) {

if (null != tx) {

try {

tx.rollback();

} catch (Exception e) {

}

}

}

} else {

result = method.invoke(originalObject, args);

}

return result;

}

}

首先注意到,上面这段代码中,并没有出现与具体应用层相关的接口或者类引用。也就

是说,这个代理类适用于所有接口的实现。

其中的关键在两个部分:

1.


return Proxy.newProxyInstance(

obj.getClass().getClassLoader(),

obj.getClass().getInterfaces(), this);

java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型

(obj.getClass().getInterfaces()) 动态构造一个代理类实例返回, 这个代理类是JVM

在内存中动态构造的动态类,它实现了传入的接口列表中所包含的所有接口。

2


public Object invoke(Object proxy, Method  method, Object[] args)

throws Throwable {

……

result = method.invoke(originalObject, args);

……

return result;

}

InvocationHandler.invoke方法将在被代理类的方法被调用之前触发。通过这个方

法中,我们可以在被代理类方法调用的前后进行一些处理,如代码中所示,

InvocationHandler.invoke方法的参数中传递了当前被调用的方法(Method) ,以及被

调用方法的参数。

同时,我们可以通过Method.invoke方法调用被代理类的原始方法实现。这样,我们

就可以在被代理类的方法调用前后大做文章。

在示例代码中,我们为所有名称以“save”开头的方法追加了JTA事务管理。

Spring中AOP实现

其中最典型的就是Spring中的配置化事务管理,先看一个例子


<beans>

<bean id="dataSource"

class="org.apache.commons.dbcp.BasicDataSource"

destroy-method="close">

<property name="driverClassName">

<value>org.gjt.mm.mysql.Driver</value>

</property>

<property name="url">

<value>jdbc:mysql://localhost/sample</value>

</property>

<property name="username">

<value>user</value>

</property>

<property name="password">

<value>mypass</value>

</property>

</bean>

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource">

<ref local="dataSource" />

</property>

</bean>

<bean id="userDAO" class="net.xiaxin.dao.UserDAO">

<property name="dataSource">

<ref local="dataSource" />

</property>

</bean>

<bean id="userDAOProxy"

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

<property name="transactionManager">

<ref bean="transactionManager" />

</property>

<property name="target">

<ref local="userDAO" />

</property>

<property name="transactionAttributes">

<props>

<prop key="insert*">PROPAGATION_REQUIRED</prop>

<prop key="get*">

PROPAGATION_REQUIRED,readOnly

</prop>

</props>

</property>

</bean>

</beans>

看看例子当中的userDAOProxy,想必大家已经猜测到Spring事务管理机制的实现原理。

是的,只需通过一个Dynamic Proxy对所有需要事务管理的Bean进行加载,并根据配

置,在invoke方法中对当前调用的方法名进行判定,并为其加上合适的事务管理代码,那

么就实现了Spring式的事务管理。

当然,Spring中的AOP实现更为复杂和灵活,不过基本原理一致。

Stuts2中的AOP实现

拦截器是Strut2的一个重要组成部分,对于Strut2框架而言,可以将其理解为一个空的容器,正是大量的内建拦截器完成该框架的大部分操作。比如,params拦截器将http请求中的参数解析出来,设置成action的属性;servlet-config直接将http请求中的httpServletRequest实例和httpServletRespon实例传给action;fileUpload拦截器负责解析请求当中的文件域,并将文件域设置为action的属性。。。。。。

对于Strut2的拦截器体系而言,当我们需要某个拦截器的时候,只需要在配置文件中应用该拦截器即可,反之亦然。不管是否应用某个拦截器,对于整个Strut2框架都不会影响,这种设计哲学,是一种可插拔的设计,具有非常好的可扩展性。

Strut2中的拦截器体系是一种AOP设计哲学,它允许开发人员以一种简单的方式来进行AOP方式的开发。

下面以一个例子来介绍Strut2中的AOP。

使用拦截器完成权限控制

l         实现拦截器

大部分web应用都涉及权限控制,当浏览者需要执行某个操作时,应用需要先检查浏览者是否登录,以及是否有足够的权限来执行该操作。

本示例要求用户登录,必须为制定用户名才可以查看系统中某个视图资源,否则直接转入登录页面。对于上面的需求,可以在每个action执行业务逻辑之前,先执行权限检查逻辑,但这种做法不利于代码复用。因为大部分action中检查权限代码都大同小异,故将这些代码逻辑放在拦截器中,将会更加优雅。

检查用户是否登录,通常都是跟踪用户的Session来完成的,通过ActionContext即可访问到Session中的属性,拦截器的intercep(ActionInvocation invocation)方法的invocation参数可以很轻易的访问到请求相关的ActionContex实例。


//权限检查拦截器继承AbstractIntercept

Public class AuthorityInterceptor extends AbstractInterceptor{

//拦截action处理的拦截方法

Public String intercept(ActionInvocation invocation){

//取得请求相关的ActionContex实例

ActionContext ctx = invocation.getInvocationContext();

Map session = ctx.getSession();

//取出名为user的session属性

String user = (String)session.get(“User”);

If(user !=null && user.equals(“scott”) ){

Return invocation.invoke();

}

Ctx.put(“tip”,”您还没有登录,请输入scott、tiger登录”);

Return Action.Login;

}

上面的拦截器代码非常简单,先从ActionInvocation 取得用户的session实例,然后从中取出user属性,通过判断属性值确定用户是否登录,从而判断是否转入登录页面。

l         配置拦截器

一旦实现了拦截器,就可以在所有需要实现权限控制的action中复用上面的拦截器。

为了使用拦截器,首先需要在struts.xml文件中定义该拦截器,定义拦截器的配置片段如下:


<interceptors>

<interceptor name=”authority” class=”qj.AuthorityInterceptor” />

</interceptors>

定义了拦截器后,可以在action中应用该拦截器,应用拦截器的配置片段如下:


<action name=”viewBook”>

<result>/WEB-INF/jsp/viewBook.jsp</result>

<interceptor-ref  name=”defaultStack” />

<interceptor-ref  name=”authority” />

</action>

这种通过拦截器控制权限的方式,显然具有更好的代码复用。

如果为了简化struts.xml文件的配置,避免在每个action中重复配置该拦截器,可以将该拦截器配置成一个默认拦截器栈。

时间: 2024-08-02 21:52:00

代理模式及其在spring与struts2中的体现的相关文章

ES6中的代理模式-----Proxy

什么是代理模式 代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式. 所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.内存中的大对象.文件或其它昂贵或无法复制的资源. 著名的代理模式例子为引用计数(英语:reference counting)指针对象. 当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少内存用量.典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象.而作用在代理者的运算会转送到原本对象.一

Java的三种代理模式简述

本文着重讲述三种代理模式在java代码中如何写出,为保证文章的针对性,暂且不讨论底层实现原理,具体的原理将在下一篇博文中讲述. 代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展. 比如有个歌手对象叫Singer,这个对象有一个唱歌方法叫sing(). 1 public class Singer{ 2 public void sing(){ 3 System.out.println("唱一首歌"); 4 } 5 } 假如你希望,通过你的某种

设计模式——10.代理模式

1. 模式动机 在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务. 通过引入一个新的对象(如小图片和远程代理 对象)来实现对真实对象的操作或者将新的对 象作为真实对象的一个替身,这种实现机制即 为代理模式,通过引入代理对象来间接访问一 个对象,这就是代理模式的模式动机. 2. 模式定义 代理模式(Proxy

代理模式-静态代理与动态代理

简介 首先感谢沽泡学院 tom 老师 代理模式是一种结构型模式 代理模式就是代理对象帮被代理对象处理一些问题, 类似中介, 客户只要结果, 中介怎么搞是他的事儿, 他可能再处理过程中赚外快什么的 代理模式的应用: spring中的aop, 日常工作中记录日志, 统计时间,权限控制等 这里我们使用一个客户端代理访问google举例, 具体细节可能不合适, 意会.意会.意会... 静态代理 /** * 一个服务器接口, 服务器有很多功能, 可以用来路由, 建站等... */ public inter

软件架构模式--代理模式

代理模式用于在结构化系统中对组件解耦.系统内各组件间采用远过程调用的方式交互.代理(组件充当组件间通讯的协调角色.提供服务的组件将其能力(服务以及特性)发布给代理,客户端均向代理请求服务,由代理将请求重定向到先前已发布过对应服务的组件进行处理. 代理模式在软件架构上具有非常明显的特点,优点与缺点都是十分的突出.代理模式的优点就是通过一个代理对象完成一系列的处理,在将来的程序改动中,就会允许动态更改.添加.删除和重新定位对象,这使开发人员的发布变得透明,符合开闭原则.代理模式能够协调调用者和被调用

设计模式之—代理模式

1.代理模式定义 Provide a surrogate or placeholder for another object to control access to it. 对其他对象提供一种代理,以控制对这个对象的访问 2.代理模式通用类图 代理模式的通用类图如下: 其中Subject为抽象主题角色: Subject为普通业务接口 RealSubject为具体主题角色: 此类为具体被代理的对象 Proxy为代理类: 此类负责执行被代理的功能,并且在处理前后做预处理和善后操作 3.通用模式的代

设计模式(四):代理模式

前言 国内程序员好像普遍对百度都没好感,而且百度近些年产生了不少负面的新闻,像16年的魏则西事件,近期的导演吴京黑白照事件,以及最近作家六六斥百度李彦宏:"你是做搜索引擎还是骗子首领",还有一件就是与程序员有关的:搜索Julia语言,在百度和Google得出首条搜索结果的差异性而被吐槽.Google虽然受欢迎,但是在国内因内容审查问题未解决而不能使用,如果我们要使用它就必须使用代理服务器,由于放置代理服务器的地区区域可以访问google,所以我们可以先访问代理服务器,通过代理服务器转发

结构型模式:代理模式

文章首发: 结构型模式:代理模式 七大结构型模式之七:代理模式. 简介 姓名 :代理模式 英文名 :Proxy Pattern 价值观 :为生活加点料 个人介绍 : Provide a surrogate or placeholder for another object to control access to it. 为其他对象提供一种代理以控制对这个对象的访问. (来自<设计模式之禅>) 你要的故事 咱们从事 IT 行业,随时都可能上网查东西,如果网络速度慢或者网络访问受限制,那是相当的

Java设计模式——代理模式

前言: 上一篇说到了策略模式.单类图上来说,它和本篇要说的代理模式还真是有些像似.都需要一个公共的接口,还有一些实现类.代理类(包装类)封装了一个接口对象,提供客户端调用.这些都很类似.不过,有一个细节需要我们注意一下,那就是这里的代理类也需要去继承这里的公共接口.而在策略模式中,包装类则不需要这么做. 概述: 代理模式就是定义一个原对象的代理对象,来帮助原对象和系统之外的业务作沟通.也就是说,如果我们不能直接或是不愿直接去使用原对象,那么我们就可以使用创建一个原对象的代理来进行操作. 本文链接