代理模式及其在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中重复配置该拦截器,可以将该拦截器配置成一个默认拦截器栈。
代理模式及其在spring与struts2中的体现的更多相关文章
- 前端MVVM模式及其在Vue和React中的体现
MVVM相关概念 Mvvm 前端数据流框架精讲 1) MVVM典型特点是有四个概念:Model.View.ViewModel.绑定器.MVVM可以是单向绑定也可以是双向绑定甚至是不绑定 2) 绑定器: ...
- spring设计模式_代理模式
代理模式应该是Spring核心设计模式之一了 先说下代理模式特性: 1.有代理人和被代理人 2.对于被代理的人来说,这件事情是一定要做的,但是我又不想做,所有就找代理人来做. 3.需要获取到被代理人的 ...
- 重学 Java 设计模式:实战代理模式「模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 难以跨越的瓶颈期,把你拿捏滴死死的! 编程开发学习过程中遇到的瓶颈期,往往是由于看不 ...
- 设计模式(十三):从“FQ”中来认识代理模式(Proxy Pattern)
我们知道Google早就被墙了,所以FQ才能访问Google呢,这个“FQ”的过程就是一个代理的过程.“代理模式”在之前的博客中不止一次的提及过,之前的委托回调就是代理模式的具体应用.今天我们就从“F ...
- Java中的代理模式
代理模式在Java Web的框架中经常使用到.比如说在对数据库的访问中,核心功能是对数据库的增删改查,而连接数据库.处理事务等功能我们在开发中也要考虑到.所以我们将数据库的CRUD抽象到接口中,然后实 ...
- 代理模式是什么?如何在 C# 中实现代理模式
代理模式 并不是日常开发工作中常常用到的一种设计模式,也是一种不易被理解的一种设计模式.但是它会广泛的应用在系统框架.业务框架中. 定义 它的 定义 就如其它同大部分 设计模式 的定义类似,即不通俗也 ...
- struts2中constant参数设置
序号 方法 说明 1 <constant name="struts.i18n.encoding" value="UTF-8"/> 指定web应用默认 ...
- Java的三种代理模式简述
本文着重讲述三种代理模式在java代码中如何写出,为保证文章的针对性,暂且不讨论底层实现原理,具体的原理将在下一篇博文中讲述. 代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下, ...
- linkin大话设计模式--代理模式
代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象的时候,客户端并不关心是否可以准确的得到这个对象,他只要一个能够提供该功能的对象而已,此时我们就可以返回该对象的代理.总而言之,客户端 ...
随机推荐
- 软件测试Web数据分析工具HttpWatch安装
1.下载破解版:http://www.pc6.com/softview/SoftView_13845.html 2.安装时引入授权文件并汉化: 3.打开IE9,菜单:管理加载项->工具栏和扩展, ...
- [Mac][phpMyAdmin] [2002] No such file or directory
我从phpMyAdmin的官网下载了最新版,将它解压到 /Library/WebServer/Documents 下,然后把文件夹改名 phpmyadmin . 接着输入在浏览器中输入 localho ...
- 剑指Offer:第一个只出现一次的字符
题目:在字符串中找出第一个只出现一次的字符.如输入"abaccdeff",这输出'b' // 第一个只出现一次的字符 #include <stdio.h> char f ...
- 【转】报错:Program "sh" not found in PATH
原文网址:http://www.cnblogs.com/SadNight/p/3406201.html (1) 报错:Program "sh" not found in PATH ...
- JavaScript中定时器
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务. setTimeout() ...
- 【转】JAVA中的反射机制
反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本 ...
- 16、传感器(Sensor)
一.什么是传感器 传感器是一种物理装置或生物器官,能够探测.感受外界的信号.物理条件(如光.热.湿度)或化学组成(如烟雾),并将探知的信息传递给其他装置或器官.国家标准GB7665—87对传感器的定义 ...
- bzoj 1060 [ZJOI2007]时态同步(树形DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1060 [题意] 求最少的增加量,使得以rt为根的树中由一个结点出发的所有到叶子结点的路 ...
- hive 中出现struct 结构化的问题
如果你使用udf,udaf,udtf中的某一个并且查询日志中出现如下之类的struct错误 java.lang.RuntimeException: Error in configuring objec ...
- 使用list和tuple
list Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> ...
