1、动态代理的定义:为其他对象提供一个代理以控制对这个对象的访问

代理类主要负责委托类的预处理消息,过滤消息,把消息传给委托类以及消息事后处理

按照代理类的创建时期,代理类可以分为2种:静态代理类(在程序运行前代理类.class文件就以及生成)和动态代理类(字节码是在程序运行时由java反射机制动态生成)

静态代理的实例:

package com.vcredit.ddcash.decision;

public class ProxyTest {
public static void main(String[] args) {
HelloService helloService = new HelloServiceImpl();
HelloServiceProxy helloServiceProxy = new HelloServiceProxy(helloService);
helloServiceProxy.say();
}

}

interface HelloService{
void say();

}
class HelloServiceImpl implements HelloService{
public void say(){
System.out.println(11);
};

}
class HelloServiceProxy implements HelloService{
public HelloService helloService;
HelloServiceProxy(HelloService helloService){
this.helloService=helloService;
}
public void say(){
System.out.println("预处理");
helloService.say();//调用被代理的HellService的say方法
System.out.println("事后处理");
};
}

2、通过api看下proxy生成代理类的2中写法:

创建某一接口 Foo 的代理:

  1. InvocationHandler handler = new MyInvocationHandler(...);
  2. Class proxyClass = Proxy.getProxyClass(
  3. Foo.class.getClassLoader(), new Class[] { Foo.class });
  4. Foo f = (Foo) proxyClass.
  5. getConstructor(new Class[] { InvocationHandler.class }).
  6. newInstance(new Object[] { handler });

或使用以下更简单的方法:

  1. Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  2. new Class[] { Foo.class },
  3. handler);
    其实第二中写法就相当于对第一中写法的封装,具体看Proxy这个类;

3、具体实例:

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  
  {  
    //在转调具体目标对象之前,可以执行一些功能处理

//转调具体目标对象的方法
    return method.invoke( proxied, args); 
   
    //在转调具体目标对象之后,可以执行一些功能处理
  }   
}

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
import sun.misc.ProxyGenerator;  
import java.io.*;  
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));//要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
        
    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();  
    }  
  }  
}

分析:当调用proxySubject.doSomething();时,就调用了$proxy0类中的doSomething()方法,在doSomething()方法中调用父类

proxy中h的invoke()方法,即InvercationHandler.invoke(),这个流程可以通过代理类的.class文件反编译后查看

部分截图:

public final void doSomething() {
   try {
   
super.h.invoke(this, m3, null);
    return;
   }
catch (Error e) {
   } catch (Throwable throwable)
{
    throw new
UndeclaredThrowableException(throwable);
   }
}

下面看下通过Proxy类的静态方法getProxyClass生成的class文件经过反编译后生成的代码:

public final class $Proxy0
extends Proxy
implements Subject{
---表名是一个最终类,此类继承了Proxy类,实现了Subject接口

public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

里面有一个带参数的构造方法,通过getProxyClass(...).getConstructor(parameterType p)//这个参数应该就是InvocationHandler这个接口类,从而通过super调用父类的带参构造器,从而给就有了InvocationHandler这个接口

protected Proxy(InvocationHandler h) {
 this.h = h;
    }

当调用$Proxy0类的doSomething()方法时:会调用h.invoke(...)方法

public final String doSomething() {
        try {
            return (String)this.h.invoke((Object)this, m3, new Object[]{});
        }
        catch (Error | RuntimeException v0) {
            throw v0;
        }
        catch (Throwable var2_2) {
            throw new UndeclaredThrowableException(var2_2);
        }
    }
看下invoke方法的3个参数 第一个指的就是被代理的类的实例也就是对应的RealSubject实例

m3指的是对应的方法

m3 = Class.forName("****.Subject").getMethod("doSomething");
第三个参数指的就是方法中的参数,没有参数就是null

再通过反射机制就可以唯一确定调用被代理类中的相关方法

4、Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

还是举例说明:

public class BookImpl{//没有实现接口
 public void add(){
  System.out.println("这是一个新增的方法");
 }

}

import java.lang.reflect.Method;

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

//创建代理类,这个类实现MethodInterceptor接口
public class BookProxy  implements MethodInterceptor {

private Object target;
 
 public BookProxy(Object target){
  this.target=target;
 }
 
 @Override
 public Object intercept(Object arg0, Method arg1, Object[] arg2,
   MethodProxy arg3) throws Throwable {
  System.out.println("事务开始");
  Object result = arg3.invokeSuper(target, arg2);
  System.out.println("事务结束");
  return result;
 }

}

//测试类

public class TestCglib {
 public static void main(String[] args){
  
 BookImpl bi = new BookImpl();

BookProxy bp = new BookProxy(bi);
 BookImpl bii = (BookImpl)Enhancer.create(bi,bp);
  bii.add();
 }

}

//输出结果

事务开始
这是一个新增的方法
事务结束

java中的动态代理的更多相关文章

  1. 使用Java中的动态代理实现数据库连接池

    2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...

  2. java中的动态代理机制

    java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...

  3. 十分钟理解Java中的动态代理

    十分钟理解 Java 中的动态代理   一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...

  4. 深度剖析java中JDK动态代理机制

    https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...

  5. 一文读懂Java中的动态代理

    从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...

  6. 代理模式与java中的动态代理

    前言    代理模式又分为静态代理与动态代理,其中动态代理是Java各大框架中运用的最为广泛的一种模式之一,下面就用简单的例子来说明静态代理与动态代理. 场景    李雷是一个唱片公司的大老板,很忙, ...

  7. java中的动态代理Proxy

    动态代理是java语言的一个神奇的地方,不是很好理解,下面来看看关键的地方. InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHa ...

  8. Java 代理模式(二) Java中的动态代理

    动态代理类 Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法: Objec ...

  9. 使用 JAVA 中的动态代理实现数据库连接池

    数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈.我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共 ...

随机推荐

  1. Linux使用jstat命令查看jvm的GC情况

    Linux使用jstat命令查看jvm的GC情况 http://www.open-open.com/lib/view/open1390916852007.html http://www.aiuxian ...

  2. mysql数据库管理工具sqlyog在首选项里可以设置默认查询分页条数和字体,改写关键字大小写

    sqlyog设置一直习惯用sqlyog来管理mysql数据库,但有三个地方用得不是很爽:1.默认查询条数只有1000条经常需要勾选掉重新查询.2.自动替换关键字大小写,有时候字段名为关键字的搞成大写的 ...

  3. 【JavaScript基础学习】关于正则表达式的完整内容

    w3cJavaScript RegExp对象  这个如果第一次看的话应该会很莫名其妙,但可以看一遍留个印象. 正则表达式30分钟入门教程 这个教程非常完整,走一遍大概能够明白怎么回事了. 正则表达式在 ...

  4. css整理-06 表和列表

    表格式化 表布局 table, display:table caption, display: table-caption thead, display: table-header-group tbo ...

  5. 寒冰王座(DGA最长路/完全背包)

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  6. 17243 Huzi酱和他的俄罗斯套娃(贪心)

    时间限制:500MS  内存限制:65535K 提交次数:15 通过次数:4 收入:12 题型: 编程题   语言: C++;C Description Huzi酱是个非常贪玩的人,除了魔方他还喜欢各 ...

  7. 循环遍历泛型集合List绑定到table

    <%@ Page Language="C#" AutoEventWireup="true" EnableViewState="false&quo ...

  8. JetS3t使用说明

    http://blog.csdn.net/hitmediaman/article/details/6636402

  9. Dockerfile完成Hadoop2.6的伪分布式搭建

    在 <Docker中搭建Hadoop-2.6单机伪分布式集群>中在容器中操作来搭建伪分布式的Hadoop集群,这一节中将主要通过Dokcerfile 来完成这项工作. 1 获取一个简单的D ...

  10. Android自动化测试-Robotium(一)简介

    一.Robotium原理 Robotium是一款Android自动化测试框架,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击.长按.滑动等).查找和断言机制的API ...