`
xupo
  • 浏览: 214896 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(转)探讨代理模式与Java反射机制的应用

阅读更多

代理模式,相信大多数人都非常熟悉,常见的实现方式是通过公共接口的方式,让我们的目标类和代理类实现同一接口,在代理类中调用目标类对象的方法。具体请看我另一个博客中的文章:Java的代理模式(通过公共接口实现) 。通过接口的方式,有个不好的地方,就是对每个目标类都要写一对与之相对应的接口和代理类,如果业务类很多,就是非常繁锁的工作了。

 

而加入反射机制的代理模式,可实现一个公共的代理类,省去我们不少功夫。Java的java.lang.reflect包及其子包中提供了Class、Method、Annotation等有用的类。下面,写个方法代理的类MethodProxy,实现动态地调用对象的方法。

 

Java代码 复制代码
  1. import java.lang.reflect.InvocationTargetException;   
  2. import java.lang.reflect.Method;   
  3. /**  
  4.  * 方法代理类  
  5.  * @author rongxinhua  
  6.  *  
  7.  */  
  8. public class MethodProxy {   
  9.        
  10.     private Class clazz;    //对象所属的类   
  11.     private Object target;  //目标对象   
  12.     private Method method;  //目标方法   
  13.     private Object[] params;    //参数数组   
  14.        
  15.     @SuppressWarnings("unchecked")   
  16.     public MethodProxy(Object target, String methodName, Object ... params) {   
  17.         rebindTarget(target, methodName, params);   //设置目标对象与方法   
  18.     }   
  19.        
  20.     /**  
  21.      * 重新设置目标对象与方法  
  22.      * @param target  
  23.      * @param methodName  
  24.      * @param params  
  25.      */  
  26.     public void rebindTarget(Object target, String methodName, Object ... params) {   
  27.         this.target = target;   
  28.         this.clazz = target.getClass();   
  29.         rebindMethod(methodName, params);   //设置目标方法   
  30.     }   
  31.        
  32.     /**  
  33.      * 重新设置目标方法  
  34.      * @param methodName  
  35.      * @param params  
  36.      */  
  37.     public void rebindMethod(String methodName, Object ...params) {   
  38.         this.params = params;   
  39.         int paramLength = params.length;   
  40.         Class[] paramTypes = new Class[paramLength];   
  41.         for(int i = 0 ; i < paramLength ; i ++ ) {   
  42.             paramTypes[i] = params[i].getClass();   
  43.         }   
  44.         try {   
  45.             this.method = clazz.getMethod(methodName, paramTypes);   
  46.         } catch (SecurityException e) {   
  47.             e.printStackTrace();   
  48.         } catch (NoSuchMethodException e) {   
  49.             e.printStackTrace();   
  50.         }   
  51.     }   
  52.        
  53.     /**  
  54.      * 动态调用已绑定的方法  
  55.      */  
  56.     public void doMethod() {   
  57.         try {   
  58.             this.method.invoke(target, params);   
  59.         } catch (IllegalArgumentException e) {   
  60.             e.printStackTrace();   
  61.         } catch (IllegalAccessException e) {   
  62.             e.printStackTrace();   
  63.         } catch (InvocationTargetException e) {   
  64.             e.printStackTrace();   
  65.         }   
  66.     }   
  67.   
  68. }  
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 * 方法代理类
 * @author rongxinhua
 *
 */
public class MethodProxy {
	
	private Class clazz;	//对象所属的类
	private Object target;	//目标对象
	private Method method;	//目标方法
	private Object[] params;	//参数数组
	
	@SuppressWarnings("unchecked")
	public MethodProxy(Object target, String methodName, Object ... params) {
		rebindTarget(target, methodName, params);	//设置目标对象与方法
	}
	
	/**
	 * 重新设置目标对象与方法
	 * @param target
	 * @param methodName
	 * @param params
	 */
	public void rebindTarget(Object target, String methodName, Object ... params) {
		this.target = target;
		this.clazz = target.getClass();
		rebindMethod(methodName, params);	//设置目标方法
	}
	
	/**
	 * 重新设置目标方法
	 * @param methodName
	 * @param params
	 */
	public void rebindMethod(String methodName, Object ...params) {
		this.params = params;
		int paramLength = params.length;
		Class[] paramTypes = new Class[paramLength];
		for(int i = 0 ; i < paramLength ; i ++ ) {
			paramTypes[i] = params[i].getClass();
		}
		try {
			this.method = clazz.getMethod(methodName, paramTypes);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 动态调用已绑定的方法
	 */
	public void doMethod() {
		try {
			this.method.invoke(target, params);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

}

 

这样就可以实现动态地调用某个对象的某个方法了,写个测试代码如下:

Java代码 复制代码
  1. public class Manager {   
  2.        
  3.     public void say() {   
  4.         System.out.println("Nobody say nothing");   
  5.     }   
  6.        
  7.     public void love(String boy, String girl) {   
  8.         System.out.println(boy + " love " + girl);   
  9.     }   
  10.        
  11. }  
public class Manager {
	
	public void say() {
		System.out.println("Nobody say nothing");
	}
	
	public void love(String boy, String girl) {
		System.out.println(boy + " love " + girl);
	}
	
}

 

 我们通过代理类来调用Manager类中的say()和love()方法,测试代码如下:

Java代码 复制代码
  1. Manager man = new Manager();    //目标对象   
  2. MethodProxy proxy = new MethodProxy(man, "say");    //方法代理对象   
  3. proxy.doMethod();   //调用被代理的方法   
  4. proxy.rebindMethod("love""Tom""Marry"); //重新绑定方法   
  5. proxy.doMethod();   //调用被代理的方法  
		Manager man = new Manager();	//目标对象
		MethodProxy proxy = new MethodProxy(man, "say");	//方法代理对象
		proxy.doMethod();	//调用被代理的方法
		proxy.rebindMethod("love", "Tom", "Marry");	//重新绑定方法
		proxy.doMethod();	//调用被代理的方法

 

这样就实现了动态代理调用对象的方法,上面代码输出结果就不贴出来了。如果要设置前置通知和后置通知等功能,也很容易实现,只需在“proxy.doMethod()”代码处的前面和后面设置即行。


扩展应用:我们在上面的MethodProxy类中加入以下方法:

Java代码 复制代码
  1. /**  
  2.  * 获取方法上的注解  
  3.  * @param anClazz 注解类  
  4.  * @return  
  5.  */  
  6. public Annotation getAnnotation(Class anClazz) {   
  7.     return this.method.getAnnotation(anClazz);   
  8. }  
	/**
	 * 获取方法上的注解
	 * @param anClazz 注解类
	 * @return
	 */
	public Annotation getAnnotation(Class anClazz) {
		return this.method.getAnnotation(anClazz);
	}

 

这个方法用来读取方法上的注解(Annotation),有什么用呢?我们写一个注解来测试下。

Java代码 复制代码
  1. @Retention(RetentionPolicy.RUNTIME)   
  2. @Target(ElementType.METHOD)   
  3. @interface Low {   
  4.     int boyAge();   //男孩法定的谈恋爱年龄   
  5.     int girlAge();  //女孩法定的谈恋爱年龄   
  6. }  
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Low {
	int boyAge();	//男孩法定的谈恋爱年龄
	int girlAge();	//女孩法定的谈恋爱年龄
}

我们要引进Annotation相关的类:

Java代码 复制代码
  1. import java.lang.annotation.Annotation;   
  2. import java.lang.annotation.ElementType;   
  3. import java.lang.annotation.Retention;   
  4. import java.lang.annotation.RetentionPolicy;   
  5. import java.lang.annotation.Target;  
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

 

我们另外写一个测试用的业务类:

Java代码 复制代码
  1. public class LoveManager {   
  2.        
  3.     @Low(boyAge=12, girlAge=10)   
  4.     public void beAbleToLove(Person boy, Person girl) {   
  5.         System.out.println(boy.getName() + " is able to love " + girl.getName());   
  6.     }   
  7.        
  8. }   
  9.   
  10. public class Person {   
  11.     private String name;   
  12.     private int age;   
  13.     public Person(String name, int age) {   
  14.         this.name = name;   
  15.         this.age = age;   
  16.     }   
  17.     //getter方法略   
  18. }  
public class LoveManager {
	
	@Low(boyAge=12, girlAge=10)
	public void beAbleToLove(Person boy, Person girl) {
		System.out.println(boy.getName() + " is able to love " + girl.getName());
	}
	
}

public class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	//getter方法略
}

 

接写上例中的proxy对象测试代码:

Java代码 复制代码
  1. LoveManager loveManager = new LoveManager();   
  2. Person boy = new Person("Tom"13);   
  3. Person girl = new Person("Marry"10);   
  4. proxy.rebindTarget(loveManager, "beAbleToLove", boy, girl); //重新绑定对象和方法   
  5. Low low = (Low)proxy.getAnnotation(Low.class);   
  6. if(boy.getAge() < low.boyAge()) {   
  7.     System.out.println(boy.getName() + "还不到法定年龄,不能谈恋爱!");   
  8. else if(girl.getAge() < low.girlAge()) {   
  9.     System.out.println(girl.getName() + "还不到法定年龄,不能谈恋爱!");   
  10. else {   
  11.     proxy.doMethod();   
  12. }  
		LoveManager loveManager = new LoveManager();
		Person boy = new Person("Tom", 13);
		Person girl = new Person("Marry", 10);
		proxy.rebindTarget(loveManager, "beAbleToLove", boy, girl);	//重新绑定对象和方法
		Low low = (Low)proxy.getAnnotation(Low.class);
		if(boy.getAge() < low.boyAge()) {
			System.out.println(boy.getName() + "还不到法定年龄,不能谈恋爱!");
		} else if(girl.getAge() < low.girlAge()) {
			System.out.println(girl.getName() + "还不到法定年龄,不能谈恋爱!");
		} else {
			proxy.doMethod();
		}

 

根据boy和girl的年龄大小,会相应地输出下列之一:

 

Text代码 复制代码
  1. Tom还不到法定年龄,不能谈恋爱!   
  2.   
  3. Marry还不到法定年龄,不能谈恋爱!   
  4.   
  5. Tom is able to love Marry  
Tom还不到法定年龄,不能谈恋爱!

Marry还不到法定年龄,不能谈恋爱!

Tom is able to love Marry

 

这就实现了,通过Java的反射来读取Annotation的值,并根据Annotation的值,来处理业务数据有效性的判断,或者面向切面动态地注入对象,或者作日志、拦截器等等。这种用法在所多框架中都常常看到, 我们在开发自己的Java组件时,不妨也采用一下吧!

 

原文地址:http://www.iteye.com/topic/629339

分享到:
评论

相关推荐

    JAVA反射与代理

    在"JAVA反射与代理"这个主题中,我们将深入探讨这两个核心概念。 首先,让我们了解反射的基本用法。当一个类的名称在运行时才被知道,反射可以帮助我们动态地创建对象。例如,我们可以使用`Class.forName()`方法...

    Java高级程序设计实战教程第三章-Java反射机制.pptx

    在本教程中,我们将深入探讨Java反射机制的核心概念、功能、API以及应用场景。 **3.1 应用场景** 反射机制在Java开发中广泛应用于框架设计,如Spring、Struts、Hibernate和MyBatis。通过读取配置文件(如XML或...

    dom4j 和java反射

    在实现Bean与XML的互转时,DOM4J和Java反射机制协同工作: 1. **XML到Bean**:首先,使用DOM4J解析XML文件,得到Element对象。然后,通过反射获取Bean的Class对象,并利用反射的newInstance()方法创建Bean实例。...

    java反射机制学习(五):工厂模式

    在本篇“java反射机制学习(五):工厂模式”中,我们将探讨如何利用反射与工厂模式结合,提升代码的灵活性和可扩展性。 首先,工厂模式是一种常用的创建型设计模式,它提供了一种创建对象的最佳方式。传统的工厂模式...

    Java反射机制详解

    在本文中,我们将深入探讨Java反射机制的基本概念、主要API以及实际应用。 1. **基本概念** 反射机制的核心在于`java.lang.Class`类,它是所有类的通用表示,通过`Class`对象我们可以获取到类的完整信息,包括构造...

    侯捷谈java反射机制.doc

    总的来说,Java反射机制提供了一种在运行时解析和操作类的能力,这对于实现某些高级功能和灵活的编程模式至关重要。理解并掌握反射的使用,可以帮助我们更好地利用Java平台的潜力,并在设计和实现复杂系统时拥有更多...

    java反射机制

    下面我们将深入探讨Java反射机制的相关知识点。 1. **什么是反射**: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;...

    JAVA反射简单例子

    下面我们将深入探讨Java反射的基本概念、重要方法以及如何在实际应用中使用它。 1. **什么是反射?** 反射是指在运行时,程序可以获取类的信息(如类名、属性、方法等),并动态地创建对象和调用方法。这使得Java...

    Java反射_Spring IOC

    Java反射机制是Java语言的一项强大功能,允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。它提供了在运行时访问类、接口、字段和方法的能力,即使这些信息在编译时未知。通过Class对象,我们...

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    在Java编程中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理)与核心业务逻辑解耦...理解Spring AOP的工作原理和反射机制对于开发高质量的Java应用至关重要。

    java反射及动态代理

    通过本文的学习,我们深入了解了Java反射机制的基本概念、应用以及其实现细节。同时,我们也探讨了动态代理机制的工作原理及其在实际开发中的应用场景。这些技术都是Java开发者必须掌握的关键技能之一,能够极大地...

    Java语言反射机制原理探析.zip

    Java语言的反射机制是其强大的特性之一,它允许在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。这一机制对于理解和利用Java的灵活性至关重要,尤其在元编程、框架设计、插件系统以及...

    java反射IBM的文章

    在IBM的文章中,作者深入探讨了Java反射机制的各个方面,为开发者提供了一个全面的理解。这篇文章是Java程序员提升技能、解决实际问题的宝贵资源。 Java反射的核心概念在于它允许程序在运行时获取类的信息,包括...

    浅谈java代理机制 .txt

    在深入探讨Java代理机制之前,我们首先需要了解代理模式的基本概念及其应用场景。代理模式是一种结构型设计模式,它为其他对象提供了一种代理以控制对这个对象的访问。在Java中,代理模式通常用于实现AOP(面向切面...

    Java 设计模式最佳实践

    在Java中,有静态代理和动态代理两种方式,动态代理通常基于Java的反射机制实现。 八、适配器模式(Adapter) 适配器模式作为两个不兼容接口之间的桥梁,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作...

    JAVA编程模式与范例_高级应用开发

    本书“JAVA编程模式与范例_高级应用开发”旨在深入探讨Java语言中的设计模式和最佳实践,以帮助开发者构建更高效、可维护和扩展性强的软件系统。下面我们将详细解析其中可能涉及的知识点。 1. **设计模式**: - **...

    Java代理学习

    代理模式广泛应用于AOP(面向切面编程)、日志、权限控制等场景。本教程将深入探讨Java中的动态代理和静态代理。 ### 静态代理 静态代理是代理模式的最基础形式,它通过创建一个实现了与目标对象相同接口的代理类...

    355.353.JAVA基础教程_面向对象(下)-接口应用:代理模式(355).rar

    在Java编程语言中,面向对象(Object-Oriented Programming,OOP)是核心特性之一,而接口(Interface)和代理模式(Proxy Pattern)是其中重要的概念。本教程将深入探讨这两个概念及其在实际开发中的应用。 接口在...

    C++与java设计模式分开详解

    此外,Java的反射机制为动态绑定和实现单例模式提供了不同的方法。 "java设计模式"这个文件可能包含了关于Java中设计模式的详细讨论,涵盖了各种模式的用途、优缺点以及如何在Java项目中有效地应用它们。你可能还会...

    类的反射机制

    6. **动态代理**: Java反射机制还支持动态代理,通过`java.lang.reflect.Proxy` 类和`java.lang.reflect.InvocationHandler` 接口,可以在运行时创建代理类,实现对目标类的增强或拦截。 实际应用场景包括但不限于...

Global site tag (gtag.js) - Google Analytics