`
KingXt
  • 浏览: 15195 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

深入理解Java的动态代理

阅读更多

      java要实现代理可以通过继承和聚合来实现,个人不推荐用继承实现,用继承实现可能使继承层次很多,这样结构就不好看,也不符合设计模式中的建议(尽量使用聚合而代替使用继承)。 看看java的动态代理是怎么实现的: 下面通过模拟java的动态代理写一个例子:

public interface Sale {

	public void sale();
}

 

package com.KingXt.proxy;

public class ComputerSales implements Sale{

	@Override
	public void sale() {
		System.out.println("--------ComputerSales--------");
	}
}

 通过实现下面的接口,用户就可以自定义代理方式(例如:方法执行前后打印出当前时间)

package com.KingXt.proxy;

import java.lang.reflect.Method;


public interface InvocationHandler{
	 public void invoke(Object proxy, Method method);
}

 简单写了一个类来测试按此类实现代理

package com.KingXt.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 赠送代理
 * @author KingXt
 *
 */
public class PresentInvocationHandler implements InvocationHandler{

	private Object object;

	public PresentInvocationHandler(Object object) {
		super();
		this.object = object;
	}


	@Override
	public void invoke(Object proxy, Method method){
		System.out.println("赠送鼠标");
		try {
			method.invoke(object, new Object[]{});
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

 这是代理生成类,通过动态生成java文件,调用jdk6带来的特性将文件编译成class,然后通过反射生成代理类

package com.KingXt.proxy;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

/**
 * 代理类实现
 * @author KingXt
 *
 */
@SuppressWarnings("unchecked")
public class Proxy {
	
	//得到项目根目录
	public static final String baseDir = System.getProperty("user.dir");
	
	public static Object newProxyInstance(Class intface, InvocationHandler h){
		if (h == null) {
		    throw new NullPointerException();
		}
		String methodString = Proxy.getMethodString(intface);
		String src = "package com.KingXt.proxy; "  +
					 "import java.lang.reflect.Method; " + 
					 "public class ProxyAny implements " + intface.getName()+ "{" + 
					 		"com.KingXt.proxy.InvocationHandler h;" + 
					  		"public ProxyAny(InvocationHandler ih){" + 
					  				"this.h = ih;" + 
					  		 "}" + 				
					  		 methodString + 
					  		 "}"+
					"}";
		String fileName = baseDir + "/src/com/KingXt/proxy/ProxyAny.java";
		File file = new File(fileName);
		//将字符串写入java文件
		try {
			FileWriter fw = new FileWriter(file);
			fw.write(src);
			fw.flush();
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return getObjectWithFile(fileName, h);
	}
	
	/**
	 * 拼接一个类的方法字符串
	 * @param intface 接口
	 * @return 方法字符串
	 */
	private static String getMethodString(Class intface){
		StringBuffer sb = new StringBuffer();
		//得到接口中的所有方法
		Method []ms = intface.getMethods();
		for(Method m : ms){
			sb.append("@Override ");
			sb.append("public void "+ m.getName() +"(){ ");
			sb.append("try { ");		  	
			sb.append("Method m = " + intface.getName() + ".class.getMethod(\"" + m.getName() + "\");");		  	
			sb.append("h.invoke(this, m);");		  	
			sb.append("}catch(Exception e){e.printStackTrace();}");
		}
		return sb.toString();
	}
	
	/**
	 * 首先将java文件动态编译,然后将编译后的class的文件load进内存,再通过反射机制生产java类
	 * @param filePath  java文件的位置
	 * @param ih		要生产java类,通过调用构造函数构建,这就必须知道构造函数的参数
	 * @return			调用反射生成的类
	 */
	private static Object getObjectWithFile(String filePath, InvocationHandler ih){
		Object o = null;
		//得到java本地编译器
		JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
		//通过java编译器得到文件管理器
		StandardJavaFileManager javaFileManager = jc.getStandardFileManager(null, null, null);
		Iterable files = javaFileManager.getJavaFileObjects(filePath);
		CompilationTask ct = null;
		//调用java编译器编译java文件
		ct = jc.getTask(null, javaFileManager, null, null, null, files);
		 
		ct.call();
		try {
			javaFileManager.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//通过URLClassLoader加载class文件
		URL urls[] = null;
		try {
			/*
			 * 这里要重点注意:
			 * 如果file:/" + baseDir + "/src这个字符串最后没有"/", URLClassLoader加载的是jar文件
			 * 否则加载的是一个目录
			 */
			urls = new URL[]{new URL("file:/" + baseDir + "/src/")};
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		URLClassLoader ul = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
		Class c = null;
		try {
			c = ul.loadClass("com.KingXt.proxy.ProxyAny");
			Constructor constr = c.getConstructor(InvocationHandler.class);
			o = constr.newInstance(ih);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return o;
	}
	
}

 

package com.KingXt.proxy;

public class Test {

	public static void main(String[] args) {
		
		//创一个电脑销售商
		ComputerSales computerSales = new ComputerSales();
		//给出销售前后可以处理的动作,例如:送鼠标
		InvocationHandler ih = new PresentInvocationHandler(computerSales);
		//创建代理
		Sale sale = (Sale) Proxy.newProxyInstance(Sale.class, ih);
		//根据代理产生的对象执行动作
		sale.sale();
	}
	
}

  

 通过上面的代码,基本上模拟了java的动态代理。但是还有很多细节性东西没实现,比如invoke函数的返回值不应该是void、同步等等。要想知道jdk具体实现可以看看jdk的源代码。还有一点要强调的是URLClassLoader的使用,很容易产生ClassNotFoundException异常。

分享到:
评论

相关推荐

    java动态代理demo

    本示例将带你深入理解Java动态代理的概念,并通过一个简单易懂的demo来演示其用法。 1. **Java动态代理概念** Java动态代理基于Java反射机制,可以在运行时动态地创建代理类和代理对象。与静态代理(即手动编写...

    java动态代理类的实例

    Java动态代理是Java语言提供的一种高级特性,它允许我们在运行时创建一个代理对象来代替某个接口或类的对象,这个代理对象能够对...分析和理解这个文件的内容,可以帮助我们深入理解Java动态代理的更多细节和应用场景。

    java动态代理实现数据库连接池

    ### Java动态代理实现数据库连接池 #### 背景与挑战 在开发应用程序时,数据库连接池...这种实现方式灵活且易于扩展,对于希望深入理解Java动态代理机制以及数据库连接池实现原理的开发者来说,具有较高的参考价值。

    java动态代理,j-dynproxies-source

    通过深入理解Java动态代理机制,我们可以灵活地扩展已有代码的功能,而无需修改原始代码,这在维护性和可扩展性方面具有很大的优势。同时,`j-dynproxies-source`这样的开源项目可以帮助我们学习和借鉴其他开发者在...

    java动态代理总结(狗星例子)

    在这个“狗星例子”中,我们将深入理解Java动态代理的工作原理,并通过具体的代码示例来阐述其核心概念。 首先,我们要知道Java动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect....

    java动态代理 经典文章(word 2007格式的)

    Java动态代理是Java编程中一个重要...以上内容是对Java动态代理技术的概述,详细的学习和理解可以通过阅读给定的文档来深入探讨。在实践中,掌握动态代理能够帮助开发者编写更灵活、可扩展的代码,提高软件的可维护性。

    2014版刘意老师动态代理讲解视频

    刘意老师的2014版动态代理讲解视频是学习这一主题的宝贵资源,结合视频中的内存图,可以帮助我们深入理解Java动态代理的工作原理及其应用。 动态代理,简单来说,就是在运行时创建一个实现了特定接口的代理类,这个...

    Java动态代理helloworld

    "示例来理解Java动态代理: ```java // 目标接口 public interface HelloWorld { void sayHello(); } // 目标实现 public class HelloWorldImpl implements HelloWorld { @Override public void sayHello() { ...

    Java 动态代理详解(学习资料)

    新的 UserService 实例 = new UserServiceImpl(); UserService proxyUserService = new UserServiceProxy(userServiceImpl);...了解和掌握动态代理技术对于深入理解 Java 并应用于实际项目开发有着重要的意义。

    java 动态代理实现AOP

    本文将深入讲解如何利用Java动态代理技术来实现AOP,以便于读者理解并实践。 #### 二、面向切面编程(AOP)简介 面向切面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式,旨在通过将横切关注点与...

    675.673.JAVA基础教程_动态代理与Java8新特性-方法引用的使用情况3(675).rar

    首先,让我们深入理解Java动态代理。动态代理基于Java的反射API实现,它允许我们在运行时创建一个实现了特定接口的代理类。这个代理类可以代理真实对象的方法调用,并在调用前后添加额外的操作。通常,我们通过`java...

    Java动态代理案例演示代码

    通过阅读和理解这个例子,你可以更深入地掌握动态代理的实现细节。如果你对某个部分有疑问,或者想要了解更多相关知识,可以参考博客文章(http://520code.net/index.php/archives/19/)进行深入学习。

    666.664.JAVA基础教程_动态代理与Java8新特性-Java8新特性内容概述(666).rar

    首先,让我们深入理解Java动态代理。动态代理是Java提供的一种机制,允许我们在运行时创建一个实现一组给定接口的类的代理实例。这个代理类可以在调用方法时执行额外的操作,如日志记录、性能监控或事务管理。动态...

    JAVA实现动态代理的简单流程

    在深入探讨Java动态代理的实现过程之前,我们首先需要理解动态代理的基本概念及其在Java中的应用价值。动态代理,顾名思义,是在运行时动态创建代理对象的一种机制,它无需在编译期就确定代理类的具体实现,而是通过...

    基于Java动态代理和反射机制实现ORM

    在IT行业中,ORM(Object-Relational Mapping,对象关系映射)是一种常用的技术,它允许...虽然现有的ORM框架如Hibernate、MyBatis已经相当成熟,但对于学习和理解Java的高级特性,这样的实践不失为一种有益的尝试。

    java动态代理例子

    这里我们将深入探讨两个主要的Java动态代理实现:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于Java接口实现,适用于目标对象实现了至少一个接口的情况。它通过`java.lang.reflect.Proxy`类和`...

    Java动态代理实现数据源连接池

    这种方式虽然相比现成的连接池库可能功能有限,但能帮助我们深入理解数据库连接池的工作原理,并且在某些定制化需求的场景下,提供了更大的灵活性。通过下载并运行提供的源码,我们可以更直观地学习这一实现方式。

    Java动态代理(Spring Aop原理)

    这篇博客的文章链接虽然没有给出具体内容,但我们可以根据Java动态代理和Spring AOP的基本概念来深入探讨相关知识点。 首先,Java动态代理允许我们在运行时创建一个实现了特定接口的新类。这个新类会代理原始类,并...

    java 动态代理实例(JDK代理与CGLIB代理)

    通过阅读和理解这些代码,你可以更深入地了解Java动态代理的工作原理和实际应用。 Java动态代理广泛应用于AOP(面向切面编程),例如Spring AOP框架,日志记录,性能监控,事务管理等场景。通过动态代理,我们可以...

Global site tag (gtag.js) - Google Analytics