`

28、设计模式之动态代理

    博客分类:
  • java
 
阅读更多

在25章讲过代理模式,这里再开一章来详细讲解代理模式,因为在spring的aop核心技术就是动态代理,有必要把动态代理机制理解透彻:


 代理模式的特征是代理类与委托类(被代理类)有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类对象的相关方法,来实现功能,故还是由委托类完成核心的操作。 

按照代理的创建时期,代理类可以分为两种。 
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。 
静态代理(如上图)每一个代理类只能为一个接口(委托类)服务,若PreBuild()和as.PostBuild()都是相同的代码,就会造成很多重复代码,这不是java语言所提倡的,解决这个问题就是使用动态代理。  
 
动态代理涉及到一个接口:InvocationHandler(调用处理器)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;    //这里的proxy指的被代理的对象,调用委托类的方法
动态代理涉及到一个类:Proxy   是完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类;
protected InvocationHandler h;      //引用了InvocationHandler接口
private static class ProxyAccessHelper {     //内部类
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{   // 生成实现类
//Class<?>[] interfaces:得到全部的接口 
动态代理类的字节码文件(.class)在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 
下面通过两个例子来了解如何使用动态代理:
public interface Interface1 {
        public void anyMethod();
}

public class Impl1 implements Interface1{
	public void  anyMethod(){
		System.out.println("实现委托类功能");
	}
}

public class ProxyImpl1 implements InvocationHandler{
	private  Object target;  //委托类,确保执行时是同一target;
	public Object createProxy(Object target) {
		this.target = target;     //确保是同一target
		//利用反射机制完成
		//Proxy.newProxyInstance(loader, interfaces, h);
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(),this); 
		//实现接口而来的this调用处理器	
	}
       //jvm底层会将这个方法  完完全全的与它要代理的 方法绑定
	 //犹如:new B().fun() 执行了new BProxy().fun()一样;
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object result=null;  
        System.out.println("委托类方法"+method.getName()+"执行前");  
        result=method.invoke(target, args);    //调用method的invoke方法
        System.out.println("动态生成的代理类:"+proxy.getClass().toString());  
        return result;  
	}
}
 测试:
Impl1 i = new Impl1();
System.out.println("委托类对象:"+i.toString());
         
ProxyImpl1 pi = new ProxyImpl1();
//要用接口接收
Interface1 ip = (Interface1) pi.createProxy(new Impl1()); 
//用Impl接收会报com.sun.proxy.$Proxy0 cannot be cast to org.demo.api.Impl1
//Impl1 ip2 = (Impl1) pi.createProxy(new Impl1()); 
ip.anyMethod();

输出:
委托类对象:org.demo.api.Impl1@1dd3812
委托类方法anyMethod执行前
实现委托类功能
动态生成的代理类:class com.sun.proxy.$Proxy0

最后生成了一$Proxy0的这么一个类(不是对象,对象是有@符号,用toString也表明是一个类), 如果改为System.out.println("动态生成的代理类:"+proxy.toString());  会报

Exception in thread "main" java.lang.StackOverflowError:at com.sun.proxy.$Proxy0.toString(Unknown Source)当应用程序递归太深而发生堆栈溢出时,抛出该错误。就是说传进来的这个对象找不到,而只能知道它属于$Proxy0类;

找遍了计算机也没找到$Proxy0.class文件,也不知道里面到底是什么内容。。

 

 

JDK的动态代理实现接口(interface1),如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。cglib是针对 类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

修改委托类(没有实现interface1接口):

 

public class Impl1 {
	public void  anyMethod(){
		System.out.println("实现委托类功能");
	}
}

 代理类要实现MethodInterceptor 接口:  添加cglib.jar 或者用spring.core.jar也可以,只是里面有些参数意义不是很明确;

 

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

//import org.springframework.cglib.proxy.Enhancer;
//import org.springframework.cglib.proxy.MethodInterceptor;
//import org.springframework.cglib.proxy.MethodProxy;

public class ProxyImpl1 implements MethodInterceptor {
	private  Object target;  //委托类,确保执行时是同一target;
	public Object createProxy(Object target) {
		//同样创建代理对象
		 this.target = target;
		 Enhancer enhancer = new Enhancer();  
	        enhancer.setSuperclass(this.target.getClass());  
	        // 回调方法  
	        enhancer.setCallback(this);  
	        // 创建代理对象  
	        return enhancer.create();  
	}

	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		 System.out.println("委托类方法"+method.getName()+"执行前");  
		 proxy.invokeSuper(obj, args);  //与jvm相似
		 System.out.println("动态生成的代理类,是个内部类?:"+obj.getClass().toString());  
		return null;  //返回为null与jvm有点不一样
	}

//	public Object intercept(Object arg0, Method arg1, Object[] arg2,
//			MethodProxy arg3) throws Throwable {
//		 System.out.println("委托类方法"+arg1.getName()+"执行前");  
//		 arg3.invokeSuper(arg0, arg2);  //与jvm相似
//		 System.out.println("动态生成的代理类,是个内部类?:"+arg0.getClass().toString()); 
//		return null;
//	}
}

 测试:

 

public static void main(String[] args) {
         Impl1 i = new Impl1();
         System.out.println("委托类对象:"+i.toString());
	 ProxyImpl1 pi = new ProxyImpl1();
	 //要用委托类接收
	 Impl1 ip2 = (Impl1) pi.createProxy(new Impl1()); 
	 ip2.anyMethod();
	}
输出:
委托类对象:org.demo.api.Impl1@153f67e
委托类方法anyMethod执行前
实现委托类功能
动态生成的代理类,是个子类:class org.demo.api.Impl1$$EnhancerByCGLIB$$5bfa5f1a

测试中要用委托类来接收,因为这个例子中没有实现接口,也就没有接口;如果最先实现了接口会是怎么样呢?

测试发现,也是实现了动态代理。

 

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

相关推荐

    动态代理设计模式 日志和源码

    动态代理设计模式是一种在运行时创建代理对象的技术,它允许我们为现有的对象提供额外的功能,如日志记录、性能监控、事务管理等,而无需修改原对象的代码。这种模式在Java和许多其他编程语言中都有应用,尤其在...

    Java设计模式——代理设计模式(静态代理和动态代理)

    代理设计模式分为静态代理和动态代理两种类型。 ### 静态代理 静态代理是在编译时就已经确定了代理关系,代理类和真实类的关系是硬编码在代理类中的。下面我们将详细介绍静态代理的实现方式: 1. **定义接口**:...

    动态代理设计模式

    详细而又简单的讲述了java动态代理设计模式

    代理模式之动态代理

    代理模式是一种设计模式,它允许在不修改原有对象的情况下,为对象添加新的功能或行为。在Java编程中,代理模式有静态代理和动态代理两种实现方式。本文将主要探讨动态代理,这是一种更灵活且适用于多种场景的技术。...

    动态代理设计模式-源码

    动态代理设计模式是一种在运行时创建对象代理的技术,它允许我们为现有的对象提供额外的功能,而无需修改原对象的代码。这种模式的核心是接口和代理类,通过接口,代理类可以与原对象进行通信,同时在代理类中添加...

    动态代理设计模式详解.pdf

    动态代理设计模式是一种编程技术,它允许在运行时创建具有相同接口的新对象,该对象能够对原对象的行为进行增强或扩展。在这个模式中,代理对象作为客户端与目标对象之间的中介,代理可以添加额外的功能,如日志记录...

    java静态代理、动态代理、装饰设计模式

    在Java编程中,代理模式是一种常见的设计模式,它允许我们为一个对象提供一个代理以控制对这个对象的访问。代理模式通常用于增加额外的功能或在访问原对象时进行额外的操作,比如日志记录、安全控制、性能统计等。...

    优秀的设计模式示例-动态代理模式

    动态代理模式是一种在运行时创建代理对象以控制或扩展原有对象行为的设计模式。它允许我们为现有的对象提供一种代理以增强其功能,而无需修改原对象的代码。动态代理模式通常用于实现对目标对象的额外操作,如日志...

    设计模式之动态代理

    动态代理在IT行业中是设计模式的一种,主要用于在不修改原有对象代码的基础上,为对象增加额外的功能或行为。这种模式在很多场景下都有应用,比如日志记录、事务管理、性能监控等。动态代理的设计思想是将目标对象与...

    java设计模式(工厂模式,动态代理,责任链模式……)实例源码

    这个压缩包中包含的实例源码涵盖了多种设计模式,包括工厂模式、动态代理和责任链模式。让我们深入探讨这些设计模式的核心概念、用途以及它们在实际编程中的应用。 1. 工厂模式:这是最基础的设计模式之一,属于...

    设计模式之动态代理与spring的aop编程

    动态代理和Spring AOP(面向切面编程)是两个关键的设计概念,它们在实现高效、模块化的系统中起着至关重要的作用。本文将深入探讨这两个概念,并结合实际应用进行解析。 首先,让我们理解什么是动态代理。动态代理...

    设计模式之代理模式demo

    代理模式是一种常用的设计模式,它在软件开发中起到了中介或者代表的作用。代理模式的主要目的是为其他对象提供一种代理以控制对这个对象的访问。通过引入代理,我们可以增加新的功能,如缓存、日志记录、访问控制等...

    设计模式之_代理模式

    **代理模式**是一种常用的设计模式,它在软件开发中扮演着重要的角色,特别是在对象的访问控制、性能优化、安全策略等方面。代理模式的核心思想是为一个对象提供一个替身,这个替身即代理对象,代理对象可以控制对原...

    设计模式之代理模式

    **设计模式之代理模式** 代理模式是软件设计模式中的一种结构型模式,它在对象交互过程中引入一个代理,代理对象负责控制对原对象的访问。这种模式的主要目的是为了解耦,提供一种替代真实对象的方式,使得客户端...

    java常用设计模式及JDK与CGLIB实现动态代理区别(源码)

    java常用设计模式及JDK与CGLIB实现动态代理区别(源码) /** * 使用cglib动态代理 * @author * */ public class BookFacadeProxy implements MethodInterceptor{ private Object target; @Override public...

    .net实现设计模式之代理模式

    代理模式是一种常用的设计模式,它在软件工程中扮演着重要的角色,特别是在.NET框架下。代理模式的核心思想是为一个对象提供一个替代品或代表,这个替代品能够控制对原对象的访问,使得客户端代码可以通过代理对象与...

    java模式设计-代理模式之动态代理.ppt

    代理模式是一种设计模式,它允许我们在不修改原有对象的情况下,为现有对象添加额外的功能或控制。在Java中,动态代理是代理模式的一种实现方式,它允许我们在运行时创建代理对象,这种方式比静态代理更加灵活。动态...

    java 设计模式之代理模式(Proxy Pattern)实现代码及设计详解:动态代理模式、静态代理模式

    Java设计模式是软件开发中的重要概念,它提供了一套通用的解决方案模板,使得代码更加可复用、可扩展。在这些模式中,代理模式(Proxy Pattern)是...对于Java开发者来说,掌握设计模式是提升专业技能的关键步骤之一。

    JAVA设计模式之代理模式实例

    代理模式是设计模式的一种,它提供了一种对目标对象进行增强或者控制访问的方式。在本实例中,我们将深入探讨Java中的代理模式及其应用。 代理模式的核心思想是为一个对象创建一个代理对象,这个代理对象在客户端和...

Global site tag (gtag.js) - Google Analytics