Java代理的作用和实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java代理的作用和实现?相关的知识,希望对你有一定的参考价值。

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 参考技术A

JDK 动态代理

动态代理的核心其实就是代理对象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。

让我们进入newProxyInstance方法观摩下,核心代码其实就三行。

这个方法需要三个参数:

    ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。

    Interfaces,是要被代理的那些那些接口。

    InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。

    //获取代理类  Class cl = getProxyClass(loader, interfaces);  
    //获取带有InvocationHandler参数的构造方法  Constructor cons = cl.getConstructor(constructorParams);  
    //把handler传入构造方法生成实例  return (Object) cons.newInstance(new Object[] h );

    一个典型的动态代理创建对象过程可分为以下四个步骤:

    1、通过实现InvocationHandler接口创建调用处理器

    IvocationHandler handler = new InvocationHandlerImpl(...);

    2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类

    Class clazz = Proxy.getProxyClass(classLoader,new Class[]...);

    3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型

    Constructor constructor = clazz.getConstructor(new Class[]InvocationHandler.class);

    4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入

    Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

    为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。

    Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
     new Class[]Subject.class, new InvocationHandlerImpl (real));

    生成的proxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际是调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的方法(Object result=method.invoke(proxied,args));
    重点Proxy.newProxyInstance,源码分析,会在其他文档中单独总结记录。类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据。

    创建代理对象时序图

    请点击输入图片描述

    获取代理类

    getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:

    在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。

    // 缓存的key使用接口名称生成的List  Object key = Arrays.asList(interfaceNames);  
    synchronized (cache)  
       do  
    Object value = cache.get(key);  
            // 缓存里保存了代理类的引用  if (value instanceof Reference)  
       proxyClass = (Class) ((Reference) value).get();  
     
    if (proxyClass != null)  
    // 代理类已经存在则返回  
       return proxyClass;  
    else if (value == pendingGenerationMarker)  
       // 如果代理类正在产生,则等待  
       try  
    cache.wait();  
        catch (InterruptedException e)  
         
       continue;  
    else  
       //没有代理类,则标记代理准备生成  
       cache.put(key, pendingGenerationMarker);  
       break;  
     
        while (true);  

    生成并加载代理类

    代理类的生成主要是以下这两行代码:

    //生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘)   proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);  
    //使用类加载器将字节码加载到内存中   proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);  

    代理类的生成过程


    ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
    JD-GUI这样的反编译软件打开jre\\lib\\rt.jar来一探究竟,以下是其核心代码的分析。

    //添加接口中定义的方法,此时方法体为空  for (int i = 0; i < this.interfaces.length; i++)  
     localObject1 = this.interfaces[i].getMethods();  
     for (int k = 0; k < localObject1.length; k++)  
        addProxyMethod(localObject1[k], this.interfaces[i]);  
       
     
    //添加一个带有InvocationHandler的构造方法  MethodInfo localMethodInfo = new MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);  
    //循环生成方法体代码(省略)  //方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略)  this.cp.getInterfaceMethodRef("InvocationHandler", "invoke", "Object; Method; Object;")  
    //将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。  localFileOutputStream = new FileOutputStream(ProxyGenerator.access$000(this.val$name) + ".class");  
    localFileOutputStream.write(this.val$classFile);

    生成的代理类源码

    那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。

    public class ProxyBusiness extends Proxy implements IBusiness, IBusiness2  
    private LogInvocationHandler h;  
    @Override  public void doSomeThing2()  
       try  
           Method m = (h.target).getClass().getMethod("doSomeThing2",null);  
           h.invoke(this, m, null);  
        catch (Throwable e)  
           // 异常处理(略)  
         

    @Override  public boolean doSomeThing()  
       try  
          Method m = (h.target).getClass().getMethod("doSomeThing", null);  
          return (Boolean) h.invoke(this, m, null);  
        catch (Throwable e)  
           // 异常处理(略)  
         
       return false;  
     
    public ProxyBusiness(LogInvocationHandler h)  
       this.h = h;  

    测试代理的代码如下:

    //测试public static void main(String[] args)  
       //构建AOP的Advice  
       LogInvocationHandler handler = new LogInvocationHandler(new Business());  
       new ProxyBusiness(handler).doSomeThing();  
       new ProxyBusiness(handler).doSomeThing2();  

    下面看一个自定义代理的实现。

    被代理类接口

    public interface Subject    
     public void doSomething();  

    被代理类

    //目标对象public class RealSubject implements Subject  public void doSomething()
       System.out.println( "call doSomething()" );
     

    调用处理器(切面)

    public class ProxyHandler implements InvocationHandler    
     private Object proxied;  
     public ProxyHandler( Object proxied )    
       this.proxied = proxied;  
       
     public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable  
    //在转调具体目标对象之前,可以执行一些功能处理System.out.println( "doSomething before" );    //转调具体目标对象的方法
       return method.invoke( proxied, args);
    //在转调具体目标对象之后,可以执行一些功能处理System.out.println( "doSomething after" );
     

    测试我们的代理实现

    public class DynamicProxy    
     public static void main( String args[] )    
       RealSubject real = new RealSubject();  
       Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
        new Class[]Subject.class, new ProxyHandler(real));
       proxySubject.doSomething();    //write proxySubject class binary data to file  
       createProxyClassFile();  
       
     public static void createProxyClassFile()    
       String name = "ProxySubject";  
       byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] Subject.class );  
       try  
         FileOutputStream out = new FileOutputStream( name + ".class" );  
         out.write( data );  
         out.close();  
       catch( Exception e )  
         e.printStackTrace();  
         
       

    运行结果:

    doSomething beforecall doSomething()doSomething after

    Proxy 接口

    Proxy 的主要静态变量

    // 映射表:用于维护类装载器对象到其对应的代理类缓存private static Map loaderToCache = new WeakHashMap();// 标记:用于标记一个动态代理类正在被创建中private static Object pendingGenerationMarker = new Object();// 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());// 关联的调用处理器引用protected InvocationHandler h;
    Proxy的构造方法// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用private Proxy() // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用protected Proxy(InvocationHandler h) this.h = h;

    ProxySubject 源码

    创建的代理类 ProxySubject.class

    import java.lang.reflect.*;  
    public final class ProxySubject extends Proxy  implements Subject  
       private static Method m1;  
       private static Method m0;  
       private static Method m3;  
       private static Method m2;  
       public ProxySubject(InvocationHandler invocationhandler)  
           super(invocationhandler);  
         
       public final boolean equals(Object obj)  
           try  
               return ((Boolean)super.h.invoke(this, m1, new Object[]  
                   obj  
               )).booleanValue();  
           catch(Error _ex)
           catch(Throwable throwable)  
               throw new UndeclaredThrowableException(throwable);  
             
         
       public final int hashCode()  
           try    
               return ((Integer)super.h.invoke(this, m0, null)).intValue();  
           catch(Error _ex)
           catch(Throwable throwable)  
               throw new UndeclaredThrowableException(throwable);  
             
         
       /*关键部分*/
       public final void doSomething()    
           try  
               // Proxy类中protected InvocationHandler h;关联的调用处理器引用
               super.h.invoke(this, m3, null);  
               return;  
           catch(Error _ex)  
           catch(Throwable throwable)  
               throw new UndeclaredThrowableException(throwable);  
             
         
       public final String toString()  
           try  
               return (String)super.h.invoke(this, m2, null);  
            catch(Error _ex)
            catch(Throwable throwable)  
               throw new UndeclaredThrowableException(throwable);  
             
         
       static  
           try  
               m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]  
                   Class.forName("java.lang.Object")  
               );  
               m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
               m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);  
               m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
           catch(NoSuchMethodException nosuchmethodexception)    
               throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
           catch(ClassNotFoundException classnotfoundexception)  
               throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
             
         

    CGLib 动态代理

    动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。

    public static void main(String[] args)  
       byteCodeGe();  
     
    public static void byteCodeGe()  
       //创建一个织入器  
       Enhancer enhancer = new Enhancer();  
       //设置父类  
       enhancer.setSuperclass(Business.class);  
       //设置需要织入的逻辑  
       enhancer.setCallback(new LogIntercept());  
       //使用织入器创建子类  
       IBusiness2 newBusiness = (IBusiness2) enhancer.create();  
       newBusiness.doSomeThing2();  
     
    /**
    * 记录日志
    */  public static class LogIntercept implements MethodInterceptor  
       @Override  
       public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable  
           //执行原有逻辑,注意这里是invokeSuper  
           Object rev = proxy.invokeSuper(target, args);  
           //执行织入的日志  
           if (method.getName().equals("doSomeThing2"))  
               System.out.println("记录日志");  
             
           return rev;  
         

本回答被提问者和网友采纳
参考技术B 当编辑并运行一个Java程序时,需要同时涉及到这四种方面。使用文字编辑软件(例如记事本、写字板、UltraEdit等)或集成开发环境(Eclipse、MyEclipse等)在Java源文件中定义不同的类 ,通过调用类(这些类实现了Java API)中的方法来访问资源系统,把源文件编译生成一种二进制中间码,存储在class文件中,然后再通过运行与操作系统平台环境相对应的Java虚拟机来运行class文件,执行编译产生的字节码,调用class文件中实现的方法来满足程序的Java API调用 。
折叠

Java动态代理

文章目录

一. 静态代理

1. 使用代理模式的作用

  1. 在原有功能的基础上增强功能。
  2. 控制访问,作为中介,不让二者直接访问。

2. 实现代理的方式

  1. 静态代理:代理类是自己手工实现的,自己创建的java类。
  2. 所要代理的目标类是确定的。
  3. 优点:简单实现,容易理解。
  4. 缺点:当目标类增加了,代理类要成倍的增加,导致代码类过多;
  5. 当你的接口功能改变,会影响众多的实现类。

3. 实现步骤

  1. 创建一个接口
  2. 创建类去实现接口
  3. 创建一个代理类,同样去实现接口。
  4. 创建一个功能类(main),调用代理类去在2中创建的类中获取想要的结果。

4. 实现代码

//1.创建一个接口

public interface Sell 
    float sell (int amount);


//2. 创建一个类去实现接
public class Factory implements Sell
    @Override
    public float sell(int amount) 
        return 85.0f;
    


//3.创建一个代理类同样去实现接口

public class Business implements Sell
    private  Factory factory = new Factory();

    public float sell(int amount) 

        float price = factory.sell(amount);
        price = price+25;
        return price;
    


//4. 主类去调用其他类,实现方法
public class ShopMain 
    public static void main(String[] args) 
        Business taobao = new Business();
        float price = taobao.sell(1);
        System.out.println("通过淘宝购买的价格为:"+price);
    


二. 动态代理

动态代理与静态代理相比,弥补静态代理的许多缺点,目标类即使很多,代理数也可以很少,当更改接口方法时也不会影响代理。

1. 介绍

在程序执行的过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类。
使用jdk的反射机制,创建对象的能力,创建的是代理类的对象。而不用你创建类文件,不用写java文件。
在程序执行时,调用jdk提供的方法才能创建代理的对象。

2. 实现步骤

  1. 创建接口,定义目标类要完成的功能。
  2. 创建目标类实现接口
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能,
    3.1 调用目标方法
    3.2 增强 功能
  4. 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。

3. 反射机制代码实现

反射机制是通过method方法,来执行类中的某个方法。

package com.Interface;

public interface Service 
    public void sayHello(String name);



package com.Interface.Impl;

import com.Interface.Service;

public class ServiceImpl implements Service 
    @Override
    public void sayHello(String name) 
        System.out.println("你好"+name);
    


package com.Interface.Impl;

import com.Interface.Service;

public class ServiceImpl2 implements Service 
    @Override
    public void sayHello(String name) 
        System.out.println("你好呀,"+name);
    


package com.company;

import com.Interface.Impl.ServiceImpl;
import com.Interface.Impl.ServiceImpl2;
import com.Interface.Service;

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

public class Main 

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException 
	// write your code here
        Service service = new ServiceImpl();
        Service service2 = new ServiceImpl2();
  /*      service.sayHello("张三");
        service2.sayHello("李四");
*/

        Method sayHello = Service.class.getMethod("sayHello", String.class);
        Object ret = sayHello.invoke(service, "李四");
        sayHello.invoke(service2, "李四");
    


4. 动态代理代码实现

此处是调用了UsbKingFactory中的方法,但经过MysellHandler代理,在没有修改原来方法的基础上增强/增加了功能,这就是代理的精辟之处。

package com.zpx.factory;

import com.zpx.service.UsbSell;
//目标类
public class UsbKingFactory implements UsbSell 
    @Override
    public float sell(int amount) 
        //目标方法
        return 85.0f;
    


package com.zpx.handler;

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

public class MySellHandler implements InvocationHandler 
    //创建一个动态的目标对象
    private Object target = null;
    //得到动态的目标对象,传入谁,给谁创建代理。
    public MySellHandler(Object target)
        this.target=target;
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        //创键目标对象代理
       Object res = null;

       res = method.invoke(target,args);

       //对目标对象进行加价。
        if (res!=null)
            float price = (float) res;
            price = price + 25;
            res = price;
        
        return res;
    


package com.zpx.service;
//目标接口
public interface UsbSell 
    float sell(int amount);



package com.zpx;

import com.zpx.factory.UsbKingFactory;
import com.zpx.handler.MySellHandler;
import com.zpx.service.UsbSell;

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

public class MainShop 
    public static void main(String[] args) 
        //1. 创建目标对象
        UsbSell factory = new UsbKingFactory();
        //2. 创建InvocaHandler对象
        InvocationHandler handler = new MySellHandler(factory);
        //3. 创建代理对象
        UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),
                handler);
        //4.通过代理执行方法。
        float price = proxy.sell(1);
        System.out.println("通过代理对象调用方法"+price);
    


以上是关于Java代理的作用和实现?的主要内容,如果未能解决你的问题,请参考以下文章

Java动态代理

Java动态代理

Java代理模式

java 静态代理

6.2Java静态代理设计模式

java 代理模式