Struts2 拦截器的底层原理

供学习.

拦截器:
1、首先要有一个目标对象,要拦截谁
2、拦截对象,拦截器本身只是一个普通的类
3、对目标对象所生成的一个代理对象,真正去执行的是代理对象,代理对象也是有若干个方法
由系统动态产生出来的,并不是我们去写出来的,代理对象的方法与目标对象的方法很类似,但是
代理对象的方法是综合了拦截器的方法和跟你的系统的目标对象的方法,将其综合起来,就形成了代
理对象的方法,也就是说代理方法是拦截器方法与目标对象方法的一个结合体

 

示例:
新增一个类Target.java  就是我们的目标对象,在使用目标对象之前要有一个接口,要求我们向对接口
编程,即先生成一个接口TargetInterface,并生成一个方法,此接口是一个普通的接口;Target类实现
TargetInterface接口,在此Target就是目标对象,我们要拦截它Target
目标有了,现在就是要写个拦截器对象:Interceptor.java  在拦截器里面我们定义两个方法:before()、
after();其拦截器跟我们平时看到的类没有什么太大的区别,之所以叫拦截器是其行为而言的;
java对象的动态代理是要用到反射;生成一个处理器类MyHandler实现反射接口InvocationHandler
其作用是将要处理的对象注入到这个处理器类里面来,动态的来调用。
在MyHandler中方法invoke()方法是真正去调用的方法。

再生成一个代理类MyProxy作用是产生一个代理,方法以getProxy()  得到一个代理,在此要用到
Proxy类,通过newProxyInstance,new一个代理出来;

 

理清的关系:
Target是目标对象,是目标,代理谁
Interceptor是拦截器,将方法动态的插入到目标对象Target方法之前或是之后去执行
在些Target与Interceptor互相不知道,Target不知道被谁插入,Interceptor也不知道插入到哪里。
因此在这声明一个MyHandler处理器,真正去调用目标对象方法,调用目标对象方法之前,执行拦截器的before

(),调用目标对象方法之后执行拦截器的after();
还有一个最重要的代理对象MyProxy,有一个getProxy()方法,传过来目标对象,在此将目标对象set到处理器里

面去myHandler.setObject(object);然后返回一个代理实例,通过代理实例来调用目标对象的方法,目标对象方

法执行之后就会去调用拦截器,则相当于拦截器对其拦截了。


总结拦截器:
角色:
1、被拦截的对象或目标,目标对象的方法被拦截
2、拦截器本身,普通的class类,行为上来说起到了拦截别人的作用
3、代理,通过代理生成对目标对象的一个代理,执行的不是目标对象,而是代理,在代理中已经插入了拦截器

,这样的作用是降低偶合
目标对象与拦截器本身是互不关联的,低偶合,通过myHandler/myporxy来偶合,在struts2中是通过xml配置文件

来偶合的.代码程次是不偶合的.

 

拦截器底层实现就是动态代理实现的。


1. struts2分发的请求处理过程:

1.1. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter()方法中:

1.1.1. 设置编码和本地化信息

1.1.2. 创建ActionContext对象

1.1.3. 分配当前线程的分发器

1.1.4. 将request对象进行封装

1.1.5. 获取ActionMapping对象, ActionMapping对象对应一个action详细配置信息

1.1.6. 执行Action请求, 进入下面方法

1.2. org.apache.struts2.dispatcher.Dispatcher.serviceAction()方法:

1.2.1. 首先获取当前请求是否已经有valueStack对象, 这样做的目的是在接受到chain跳转方式的请求时, 可以直接接管上次请求的action

1.2.2. 如果请求中没有ValueStack对象, 获取当前线程的ActionContext对象

1.2.3. 从ActionContext中获取ValueStack

1.2.4. 将事先处理好的请求中的参数put到ValueStack中

1.2.5. 获取ActionMapping中配置的namespace, name, method值

1.2.6. 根据配置获取当前Action的代理对象ActionProxy(这个过程中会创建Action对象, 同时返回的代理对象是StrutsActionProxy的实例)

1.2.7. 向request中设置ValueStack对象

1.2.8. 进入ActionProxy的处理

1.3. org.apache.struts2.impl.StrutsActionProxy.execute()方法:

1.3.1. 准备上下文环境

1.3.2. StrutsActionProxy是继承自com.opensymphony.xwork2.DefaultActionProxy的, 在这个代理对象内部实际上就持有了com.opensymphony.xwork2.DefaultActionInvocation的一个实例的

1.3.3. DefaultActionInvocation对象中保存了Action调用过程中需要的一切信息

1.3.4. 此时, 调用它的invoke方法

1.4. com.opensymphony.xwork2.DefaultActionInvocation.invoke()方法:

1.4.1. 首先会顺序的递归执行当前Action中所配置的所有的拦截器, 直到拦截器遍历完毕调用真正的Action

1.4.2. 通过调用DefaultActionInvocation的invokeActionOnly()方法去反射调用Action, 调用过程中, 会从当前的invocation对象中得到Action的实例, 并通过代理对象获得配置信息.

1.5. com.opensymphony.xwork2.DefaultActionInvocation.invokeAction()方法:

1.5.1. 反射获得当前请求分发的Action中的方法对象

1.5.2. 以传入的Action实例反射调用该处理方法

1.5.3. 如果返回的结果不是com.opensymphony.xwork2.Result的实例, 返回强转为字符串的结果.

1.6. 回到1.4所在方法继续:

1.6.1. 将invokeAction返回的resultCode存储到当前的invokeAction实例中

1.6.2. 进入result处理

1.7. com.opensymphony.xwork2.DefaultActionInvocation.executeResult()方法:

1.7.1. 创建result对象(com.opensymphony.xwork2.DefaultActionInvocation.createResult()方法)

1.7.1.1. 如果当时调用Action返回了Result对象, 则直接返回

1.7.1.2. 否则, 通过proxy对象获取配置信息, 根据resultCode获取到Result对象

1.7.2. 使用ognl翻译result中的用${}和%{}标识引用ValueStack中的值的参数.

1.7.3. 调用执行result

1.8. org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute()方法

1.8.1. 准备执行环境: request, pageContext等等

1.8.2. 判断有没有合适的分发器, 如果没有, 发404消息

1.8.3. 在request对象中设定两个属性:

1.8.3.1. struts.view_uri: 分发之后的url地址

1.8.3.2. struts.request_uri: 真正请求的url地址

1.8.4. 发送真正的响应信息

1.9. 至此, Action的处理完毕, 回归到1.4.1中指明的递归调用那里, 逐步的返回并执行每个拦截器的invokeAction.invoke()后面的代码, 从这里也就可以看出拦截器的机制.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值