拦截器的意义:
大家都知道,DRY(Don't Repeat Yourself,不要书写重复的代码)规则是软件开发过程中的一条重要法则,遵守该规则所开发出来的系统将会具有较好的可维护性。拦截器思想与此也是有相似点的,可以这样理解:
拦截器是对调用方法的改进。实际上,当称某个实例是一个拦截器时,这是就其行为上而言;但从代码角度来看,拦截器就是一个类,这个类也包含方法,只是这个方法是个特殊方法,它会在目标方法
调用之前“自动”执行。
PS:上面的自动执行的自动被加上了引号,这是因为在 编程过程中,没有自动的事情,任何事情都是代码驱动的。这里的自动是指无需开发者关心,由系统来驱动。
大部分时候,拦截器方法都是通过代理的方式来调用的,下面以JDK动态代理为例来介绍如何调用拦截器方法:
下面先定义一个简单的Person接口,因为JDK动态代理只能对实现了接口的实例来生成代理,因此必须提供一个Person接口,该接口代码如下:
public interface Person{
//getName方法声明
public void getName();
//getAge方法声明
public void getAge();
}
上面接口里简单定义了两个方法,并未提供方法实现,为了能正常使用该Person实例,必须提供该接口的实现类,实现类PersonImpl代码如下:
public class PersonImpl implements Person{
//getName方法实现
public void getName(){
System.out.println("My name is jack!");
}
//getAge方法实现
public void getAge(){
System.out.println("I am 23!");
}
}
上面代码没有丝毫的特别之处,该Person的实现类仅仅为每个方法提供了一个简单实现。
系统用户拦截Person实例的拦截器类如下:
//定义系统拦截器类
public class PersonIntercepter{
//第一个拦截器方法
public void method1(){
System.out.println("=====模拟通用方法一=====");
}
//第二个拦截器方法
public void method2(){
System.out.println("=====模拟通用方法二=====");
}
}
上面的拦截器没有我们想象的那么神奇,拦截器也是一个普通的Java类。称它为拦截器,只是就它的行为而言,并不是它在代码实现上与普通Java类有什么特别之处。
假设我们要在getName方法执行前后分别调用拦截器里的方法,系统应该如何实现呢?关键是下面的ProxyHandler类,该类需要实现InvocationHandler接口,该接口是JDK反射体系里的一个接口,它可以动态调用目标对象的方法。
public class ProxyHandler implements InvocationHandler{
//需要被代理的目标对象
private Object target;
//创建拦截器实例
PersonIntercepter pi = new PersonIntercepter();
//执行代理的目标方法时,该invoke方法会被自动调用
public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
Object result = null;
//如果被调用方法的方法名为getName
if(method.getName().equals("getName")){
//调用拦截器方法1
pi.method1();
result = method.invoke(target, args);
//调用拦截器方法2
pi.method2();
}else{
result = method.invoke(target, args);
}
return result;
}
//用户设置传入目标对象的方法
public void setTarget(Object o){
this.target = o;
}
}
从上面代码中看出,这个类与前面的Person类没有丝毫关联之处,如果硬要说有关联,也就是在invoke方法中判断了目标方法的方法名是否为getName——至于这个方法是否属于Person实例,它并不关心。
通过ProxyHandler的帮助,系统实现了在执行getName方法之前,调用拦截器的method1方法;在指定getName方法之后,调用拦截器的method2方法。
正因为上面类与被拦截对象没有丝毫耦合,从而提供了更好解耦,以及更好的可扩展性。但上面的类与两个地方耦合了:
1、与拦截器类耦合:上面类固定使用PersonIntercepter拦截器。
2、与被拦截的方法耦合:上面类指定拦截名为getName的方法。
正是通过这两个地方的耦合,系统才能够知道在调用哪个拦截器的方法,以及需要拦截的目标对象。当然,这两个耦合也需要解决,通常的解决方案是将拦截器类放在配置文件中指定,将需要被拦截的目标方法也放在配置文件中指定。
系统还需要提供一个代理工厂,代理工厂的主要作用就是根据目标对象生成一个代理对象。
public class MyProxyfactory{
/**
* 实例Service对象
* @param serviceName String
* @return Object
*/
public static Object getProxy(Object object){
//代理的处理类
ProxyHandler handler = new ProxyHandler();
//把该Person实例托付给代理操作
handler.setTarget(object);
//第一个参数是用来创建动态代理的ClassLoader对象,只要该对象能访问Person接口即可
//第二个参数是接口数组,正是代理该接口数组
//第三个参数是代理包含的处理实例
return Proxy.newProxyInstance(PersonImpl.class.getClassLoader(), object.getClass().getInterfaces(), handler);
}
}
Proxy.newProxyInstance方法根据接口数组动态创建代理类实例,接口数组通过object.getClass().getInterfaces()方法获得,创建的代理类是JVM在内存中动态创建,该类实现传入
参数里接口数组中的全部接口。因此,Dynamic Proxy要求被代理的必须是接口的实现类,否则无法为其构造相应的动态实例。
从上面的介绍可以看出,代理工厂负责根据目标对象和对应的拦截器生成新的代理对象,代理对象里的方法是目标方法和拦截器方法的组合。正是通过这种方式,实现了在目标方法之前或者之后,自动调用拦截器方法的目的。
下面是主程序:
public class Test{
public static void main(String[] args){
//创建一个Person实例,该实例将被作为代理的目标对象
Person targetObject = new PersonImpl();
Person person = null;
//以目标对象创建代理
Object proxy = MyProxyFactory.getProxy(targetObject);
if(proxy instanceof Person){
person = (Person)proxy;
}
//测试代理的方法
person.getName();
person.getAge();
}
}
上面代码先创建了一个Person实例作为目标对象,然后以该目标对象作为“蓝本”,创建该对象的代理对象——代理对象里的方法,是拦截器方法和目标对象方法的组合,这就是为什么可以在执行目标方法的前后,执行拦截器方法的原因。
拦截器和AOP的关系:
拦截器与AOP(Aspect Orient Program,面向切面编程)是密切相关的,AOP从程序运行角度来考虑程序的流程,取得业务处理过程的切面,在特定切面通过系统自动插入特定方法。
AOP面向的是程序运行中各个步骤,以一种松耦合方式来组合业务处理的各个步骤。
在AOP的编程方式中,有三个重要概念:
1、目标对象:包含被拦截方法的原始对象。
2、被插入的处理方法:定义在拦截器中,会在被拦截方法之前、之后自动执行的方法。
3、代理对象:以目标对象为蓝本,由系统创建的新对象。
在上面的三个概念中,被插入的处理方法不能独立存在,因为方法必须有一个存在的载体——这个载体就是拦截器,拦截器就是包含处理方法的特殊实例。
代理对象也称为AOP代理,就是由系统动态生成的一个对象,该对象将代替目标对象来使用,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与
目标对象的方法存在差异:AOP方法在特定切面插入拦截器方法,在处理之间回调目标对象的方法,从而实现了在执行目标方法之前或之后调用拦截器方法,放佛拦截器
拦截了原有的目标方法一样。
事实上,Struts2的拦截器机制来自于WebWork的拦截器机制,这种拦截器机制就是基于AOP的思想。
分享到:
相关推荐
Struts拦截器是Java Web开发框架Struts2中的核心组件之一,它允许开发者在Action执行前后插入自定义的处理逻辑,实现AOP(面向切面...这种基于JDK动态代理实现的Struts拦截器,是Java Web开发中一种强大的设计模式。
拦截器通常通过动态代理技术来实现,其中最常见的是JDK动态代理。在Struts2中,当请求到达时,框架会创建一个代理对象来包装原始的Action对象。这个代理对象会在调用Action的方法之前先调用拦截器的方法,执行相应的...
Struts1 框架是Java Web开发中的一个经典MVC框架,它的核心组件之一就是拦截器(Interceptor)。拦截器在Struts1中扮演着重要角色,它允许开发者在动作执行前后插入自定义的逻辑,比如日志记录、权限验证、事务管理...
2. **拦截器**:Struts2的一个强大特性是拦截器,它们是可重用的代码片段,可以插入到Action调用链中,以实现诸如日志、权限检查、事务管理等功能。在配置文件中,通过InterceptorStack元素可以定制拦截器栈。 3. *...
它的主要特点包括可插拔的架构、强大的拦截器机制以及丰富的动作和结果类型。Struts2允许开发者通过配置XML文件或者注解来定义应用程序的控制流,极大地提高了开发效率和代码的可维护性。在压缩包中,“struts2”...
- `Interceptor`接口:提供拦截器功能,可以在Action执行前后插入自定义逻辑,如日志、权限检查等。 - `Result`接口:定义了动作执行后如何展示结果,如转发、重定向等。 **Spring API** Spring是一个全面的Java...
struts.xml 文件用于配置 Struts2 的核心配置,包括 Action 的映射、结果类型、拦截器等。web.xml 文件用于配置 Web 应用程序的容器相关信息,包括 Servlet 的配置、Filter 的配置等。 5. Struts2 的 Action: ...
9. **深入研究**:进一步学习Struts2的高级特性,如动态方法调用、自定义拦截器、Struts2与其他框架的整合等。 10. **不断更新**:Struts2虽已有些年份,但它的核心思想和许多机制在现代Web框架中依然适用。了解...
- `struts2-core.jar`:包含框架的核心API,如ActionSupport类、Result接口和拦截器机制。 - `xwork-core.jar`:XWork是Struts2的基础,提供了对象容器、类型转换、动态方法调用等功能。 - `ognl.jar`:Object-...
`struts.xml`是Struts2的主要配置文件,它定义了Action、结果、拦截器等组件。一个基本的`struts.xml`模板如下所示: ```xml <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration...
同时,要配置拦截器,以实现Struts2的核心功能,如模型驱动、文件上传等。 3. **ExtJS集成**:在前端,你需要引入ExtJS库,并创建视图组件,如Grid、Form、Panel等。通过Ajax请求与Struts2 Action进行通信,获取...
- `struts.xml`:Struts2的配置文件,定义了Action、结果类型、拦截器等。 3. **lib目录**:包含所有必要的库文件,包括Struts2框架的JAR包和其他依赖库。 4. **WebContent或html目录**:存放静态资源,如HTML...
3. **拦截器(Interceptors)**:Struts2的拦截器机制允许在Action执行前后插入自定义逻辑,如日志、权限检查等。 4. **模型驱动(ModelDriven)**:一种设计模式,让Action类仅包含业务逻辑,而将数据模型分离出来...
Struts2使用它进行动态代理,确保新版本的Javassist支持Struts2的新特性和修复。 2. **配置文件的调整**:Struts2的配置文件(如struts.xml)可能会因版本升级而需要调整。例如,新的版本可能会引入新的拦截器或...
9. **拦截器(Interceptor)**:Struts2的拦截器是处理请求和响应的关键组件,它们在Action执行前后运行,实现如日志、验证、事务管理等功能。 10. **类型转换和插件**:Struts2具有强大的类型转换能力,可以自动将...
Interceptor则是拦截器,可以在Action执行前后进行额外的操作,如日志记录、权限检查等。 搭建Struts2的开发环境,我们需要以下步骤: 1. **安装Java环境**:确保系统已安装Java JDK,并设置好环境变量。 2. **...
总的来说,Struts2是结合了Struts 1的广泛采纳和WebWork的创新设计的产物,它通过提供非侵入式设计、强大的数据绑定和可扩展的拦截器机制,为Java Web开发者提供了一个更高效、灵活的开发平台。
2. **拦截器**:Struts2的核心特性之一是拦截器。拦截器在Action调用前后执行,用于添加通用功能,如日志记录、事务管理、性能监控等。它们可以通过配置文件灵活地组合和插入到请求处理流程中。 3. **插件支持**:...
Struts2是一个流行的Java web应用程序框架,用于构建MVC(模型-视图-控制器)架构的应用。...通过本教程,你将能够掌握Struts2的基础知识,进一步深入学习Struts2的拦截器、国际化、异常处理等高级特性。
Struts2是Java EE开发中一个非常流行的MVC框架,用于构建可维护、可扩展的Web应用程序。在开始使用Struts2之前,...在实际开发中,你可能还需要了解更多关于Struts2的特性,如拦截器、插件、国际化、异常处理等内容。