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

Java的动态代理实现

 
阅读更多

1. 问题

在许多情况下,我们需要使用代理模式来解决问题。如下为代理模式的类图。


 

 

 

如下为使用 Java 实现代理模式的一个例子:

 

package com.demo.dynamicproxy;

public interface IHello {

	public void sayHello() ;
}

 

package com.demo.dynamicproxy;

public class HelloProxy implements IHello {

	private IHello speaker = new HelloSpeaker();
	
	public HelloProxy(IHello hello) {
		this.speaker = hello;
	}
	
	private void preRequest() {
		System.out.println("prepare");
	}
	
	private void postRequest() {
		System.out.println("applaud");
	}
	
	@Override
	public void sayHello() {
		preRequest();
		this.speaker.sayHello();
		postRequest();

	}

}

 

package com.demo.dynamicproxy;

/**
 * @author Xiechangming
 * 
 */
public class HelloSpeaker implements IHello {

	@Override
	public void sayHello() {
		System.out.println("Hello,world");

	}

}

 

package com.demo.dynamicproxy;

public class ProxyTest {

	public static void main(String...args){
		
		//static proxy
		HelloProxy proxy = new HelloProxy(new HelloSpeaker());
		
		proxy.sayHello();
		
		//dynamic proxy
		HelloHandler handler = new HelloHandler();
		
		IHello dynamicProxy = (IHello)handler.bind(new HelloSpeaker());
		
		dynamicProxy.sayHello();
	}
}

 

 

正如你所见,需要显示地实现一个代理类,这就是静态代理模式。 如果需要被代理的方法很多,且代理的逻辑相同,势必要为每种方法实现一个代理类,在程序规模稍大是就会产生很多代理类。该如何解决呢?

2. 解决方案

JDK1.3 中,引入了动态代理类,用来解决相同的代理逻辑可以为多种被代理类重复使用。 JDK 动态代理中包含一个类和一个接口:  
InvocationHandler
接口:
 
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 

参数说明:
 
Object proxy
:指被代理的对象。
 
Method method
:要调用的方法
 
Object[] args
:方法调用时所需要的参数 

该方法就是实现代理逻辑的地方,类似于 ProxySubject  

Proxy 类:  
Proxy
类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
 
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
参数说明:
 
ClassLoader loader
:类加载器
 
Class<?>[] interfaces
:得到全部的接口
 
InvocationHandler h
:得到 InvocationHandler 接口的子类实例  

该方法返回真实的代理类的一个对象,该代理类是 JDK 动态生成的。如下是一个动态代理模式的实例:

package com.demo.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HelloHandler implements InvocationHandler {

	private Object delegate;
	
	public Object bind(Object delegate) {
		this.delegate = delegate;
		
		return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
	}
	private void preRequest() {
		System.out.println("prepare");
	}
	
	private void postRequest() {
		System.out.println("applaud");
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		preRequest();
		method.invoke(this.delegate, args);
		postRequest();
		return null;
	}

}

 

 

 

 

package com.demo.dynamicproxy;

public class ProxyTest {

	public static void main(String...args){
		
		//static proxy
		HelloProxy proxy = new HelloProxy(new HelloSpeaker());
		
		proxy.sayHello();
		
		//dynamic proxy
		HelloHandler handler = new HelloHandler();
		
		IHello dynamicProxy = (IHello)handler.bind(new HelloSpeaker());
		
		dynamicProxy.sayHello();
	}
}

 

 

3.  实现原理

通过查看 Proxy 的源代码,可以对动态代理模式的实现原理有一个大致的了解 :

下面是 newProxyInstance 的实现,从中可以看出关键是调用 getProxyClass 方法 获得最终的代理类,该代理类是动态生成

public static Object newProxyInstance(ClassLoader loader,
					  Class<?>[] interfaces,
					  InvocationHandler h)
	throws IllegalArgumentException
    {
	if (h == null) {
	    throw new NullPointerException();
	}

	/*
	 * Look up or generate the designated proxy class.
	 */
	Class cl = getProxyClass(loader, interfaces);

	/*
	 * Invoke its constructor with the designated invocation handler.
	 */
	try {
	    Constructor cons = cl.getConstructor(constructorParams);
	    return (Object) cons.newInstance(new Object[] { h });
	} catch (NoSuchMethodException e) {
	    throw new InternalError(e.toString());
	} catch (IllegalAccessException e) {
	    throw new InternalError(e.toString());
	} catch (InstantiationException e) {
	    throw new InternalError(e.toString());
	} catch (InvocationTargetException e) {
	    throw new InternalError(e.toString());
	}
}

 

 

 

 


 下面是 getProxyClass 的主要实现

public static Class<?> getProxyClass(ClassLoader loader, 
                                         Class<?>... interfaces)
	throws IllegalArgumentException
    {
	…

	Class proxyClass = null;//声明要动态生成的类
…
String proxyName = proxyPkg + proxyClassNamePrefix + num; //定义动态生成的类的名字
		/*
		 * Verify that the class loader hasn't already
		 * defined a class with the chosen name.
		 */

		/*
		 * Generate the specified proxy class.
		 */
		byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
		    proxyName, interfaces);//调用generateProxyClass方法生成动态类的.class文件的二进制,Sun的内部实现
		try {
		    proxyClass = defineClass0(loader, proxyName,
			proxyClassFile, 0, proxyClassFile.length);//.class文件的二进制导入到JVM,获得类的实例。这是一个本地方法。
		} catch (ClassFormatError e) {
		    /*
		     * A ClassFormatError here means that (barring bugs in the
		     * proxy class generation code) there was some other
		     * invalid aspect of the arguments supplied to the proxy
		     * class creation (such as virtual machine limitations
		     * exceeded).
		     */
		    throw new IllegalArgumentException(e.toString());
		}
	    }
	    // add to set of all generated proxy classes, for isProxyClass
	    proxyClasses.put(proxyClass, null);

	}
 …
	return proxyClass;//返回生成的类。
    }


 

 

 

 

4. 不足

该代理模式要求被代理的类必须要实现接口,如果被代理的类没有实现接口,则不能使用动态代理模式。那么有什么更好的方式来代理没有实现接口的类的方法呢?这就要用到开源软件 CBLib 了。下面是是使用 CGLib 实现的例子:

package com.demo.dynamicproxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

	private void preRequest() {
		System.out.println("prepare");
	}

	private void postRequest() {
		System.out.println("applaud");
	}

	public Object newProxyInstance(Object target) {
		Enhancer enhancer = new Enhancer();
		
		enhancer.setSuperclass(target.getClass());
		
		enhancer.setCallback(this);
		
		return enhancer.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		preRequest();
		proxy.invokeSuper(obj, args);
		postRequest();

		return null;
	}

}
 
package com.demo.dynamicproxy;

public class ProxyTest {

	public static void main(String... args) {

//		// static proxy
//		HelloProxy proxy = new HelloProxy(new HelloSpeaker());
//
//		proxy.sayHello();
//
//		// dynamic proxy
//		HelloHandler handler = new HelloHandler();
//
//		IHello dynamicProxy = (IHello) handler.bind(new HelloSpeaker());
//
//		dynamicProxy.sayHello();

		// Cglib
		CglibProxy cglibProxy = new CglibProxy();
		
		IHello helloProxy = (IHello)cglibProxy.newProxyInstance(new HelloSpeaker());
		
		helloProxy.sayHello();

	}
}
 

CGLib 本质上是动态生成了一个被代理类的子类,并 Override 了被代理的方法,因此被代理的类中方法不能将方法定义为 final ,否则就类似于直接对被代理类的调用,就如实例中,只会输出“Hello,world"。

 

  • 大小: 13.5 KB
分享到:
评论

相关推荐

    用Java动态代理实现AOP

    Java动态代理实现AOP Java动态代理是实现Aspect Oriented Programming(AOP)的重要手段。在Java中,动态代理可以通过java.lang.reflect InvocationHandler接口和java.lang.reflect.Proxy类来实现。AOP的主要思想...

    java 动态代理实现AOP

    ### Java动态代理实现AOP详解 #### 一、引言 随着软件开发复杂度的提升,传统的面向对象编程(OOP)已经难以满足现代软件工程的需求。为了更好地管理跨切面的关注点,如日志记录、性能监控、安全控制等,面向切面...

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

    总的来说,Java动态代理实现数据源连接池的核心思想是利用`InvocationHandler`来拦截对数据库操作的调用,通过代理对象在每次操作前后进行连接的获取和释放,从而实现连接池的逻辑。这种方式虽然相比现成的连接池库...

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

    ### Java动态代理实现数据库连接池 #### 背景与挑战 在开发应用程序时,数据库连接池是一个常用且重要的组成部分。频繁地建立和断开数据库连接不仅效率低下,还可能导致性能瓶颈。为了解决这一问题,引入了数据库...

    用Java动态代理实现委托模式

    下面我们将详细探讨如何使用Java动态代理实现委托模式,以及相关的源码和工具应用。 首先,理解委托模式的基本概念。委托模式通常由三部分组成:委托者(Delegate)、被委托者(Subject)和客户端(Client)。委托...

    java动态代理实现详解

    Java 动态代理是Java平台提供的一种强大的工具,它允许我们在运行时动态生成代理类,这些代理类可以实现一组指定的接口,同时还能在方法调用前后添加自定义的行为。这种机制大大简化了面向切面编程(AOP)和事件监听...

    使用Java动态代理实现一个简单的网络请求拦截器.txt

    ### 使用Java动态代理实现一个简单的网络请求拦截器 #### 一、引言 在软件开发过程中,为了增强程序的功能或方便进行调试与监控,我们常常需要在不改变原有业务逻辑的基础上,添加一些额外的行为(如日志记录、...

    java 动态代理实现注解日志拦截

    在本场景中,我们将探讨如何使用Java动态代理结合注解来实现日志拦截,以便在调用方法时记录相关的日志信息。 首先,让我们了解Java动态代理的基本概念。在Java中,动态代理主要由两个类实现:`java.lang.reflect....

    java动态代理实现自定义连接池

    Java中的动态代理是通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口实现的。Proxy类用于创建动态代理实例,而InvocationHandler接口则定义了调用处理程序的逻辑,即当代理对象的方法被...

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

    - `设计模式:用Java动态代理实现AOP.docx`可能包含了如何使用Java动态代理来实现设计模式,尤其是代理模式,以达到AOP的效果。 - `Spring AOP入门实例详解.docx`可能涵盖了Spring AOP的基本概念、配置以及如何...

    JAVA动态代理实现Demo(JDK动态代理和CGLIB动态代理)

    Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...

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

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

    Java动态代理实现 Proxy InvocationHandler

    在本文中,我们将深入探讨这两个关键组件以及如何使用它们来实现动态代理。 ### 1. Java动态代理的基本概念 动态代理允许我们在运行时创建一个实现了特定接口的新类。这个新类(代理类)可以代理原始类(目标类)...

Global site tag (gtag.js) - Google Analytics