动态代理和静态代理到底有什么区别,好处在哪里?

LAN接口分配ispDNS功能测试 环境拓扑: PPPoE Server----OLT----ONU----PC Server IP:20.20.20.1 ONU:LAN侧DCHP开启 DNS:域名解析 ispDNS功能点如下图所示: 1.、勾选上 ispDNS 选项框 时,直连的PC 分配的DNS是:上行网关IP及上行DNS(好、跟 WAN连接获取到的DNS一致);如下图所示:查看结果时最好是PC重新释放下地址:执行命令:ipc... 阅读详情

 

一、概念

  代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。

静态代理
  1. 由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了
  2. 静态代理通常只代理一个类
  3. 静态代理事先知道要代理的是什么
动态代理
  1. 在程序运行时,运用反射机制动态创建而成
  2. 动态代理是代理一个接口下的多个实现类
  3. 动态代理不知道要代理什么东西,只有在运行时才知道
  • 动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。
  • 还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。

二、静态代理类

 如下, HelloServiceProxy类是代理类,HelloServiceImpl类是委托类,这两个类都实现了HelloService接口。其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用HelloServiceImpl类的相关方法来提供特定服务的。HelloServiceProxy类的echo()方法和getTime()方法会分别调用被代理的HelloServiceImpl对象的echo()方法和getTime()方法,并且在方法调用前后都会执行一些简单的打印操作。
由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。

例程1 HelloService.java

package proxy;
import java.util.Date;

public interface HelloService{
public String echo(String msg);
public Date getTime();
}

 例程2 HelloServiceImpl.java

package proxy;

import java.util.Date;

public class HelloServiceImpl implements HelloService{

    public String echo(String msg){
        return "echo:"+msg;
    }

    public Date getTime(){
        return new Date();
    }

}

例程3 HelloServiceProxy.java 

package proxy;

import java.util.Date;

public class HelloServiceProxy implements HelloService{

    //表示被代理的HelloService 实例
    private HelloService helloService;

    public HelloServiceProxy(HelloService helloService){
        this.helloService=helloService;
    }

    public void setHelloServiceProxy(HelloService helloService){
        this.helloService=helloService;
    }

    public String echo(String msg){
        //预处理
        System.out.println("before calling echo()");
        //调用被代理的HelloService 实例的echo()方法
        String result=helloService.echo(msg);
        //事后处理
        System.out.println("after calling echo()");
        return result;
    }

    public Date getTime(){
        //预处理
        System.out.println("before calling getTime()");
        //调用被代理的HelloService 实例的getTime()方法
        Date date=helloService.getTime();
        //事后处理
        System.out.println("after calling getTime()");
        return date;
    }
}

例程4 Client1.java 

在Client1类的main()方法中,先创建了一个HelloServiceImpl对象,又创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对象的echo()方法。

package proxy;

public class Client1{

    public static void main(String args[]){
        HelloService helloService=new HelloServiceImpl();
        HelloService helloServiceProxy=new HelloServiceProxy(helloService);
        System.out.println(helloServiceProxy.echo("hello"));
    }
}

运行Client1 类,打印结果如下:

before calling echo()

after calling echo()

echo:hello

 

注意:例程3 的HelloServiceProxy类的源代码是由程序员编写的,在程序运行前,它的.class文件就已经存在了,这种代理类称为静态代理类。

 

三、动态代理类

   与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

Proxy类提供了创建动态代理类及其实例的静态方法。
(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:

public static Class<?> getProxyClass(ClassLoader loader,Class<?>[ ] interfaces) throwsIllegalArgumentException

loader指定动态代理类的类加载器
interfaces指定动态代理类需要实现的所有接口

(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:

public static Object newProxyInstance(ClassLoader loader,Class<?>[ ] interfaces,InvocationHandler handler) throws
     IllegalArgumentException

loader指定动态代理类的类加载器(定义了由哪个ClassLoader对象来对生成的代理对象进行加载)
interfaces指定动态代理类需要实现的所有接口(表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态))
handler指定与动态代理类关联的InvocationHandler 对象(表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler)


以下两种方式都创建了实现Foo接口的动态代理类的实例:

  1. //创建InvocationHandler对象
    InvocationHandler handler = new MyInvocationHandler(...);

    //创建动态代理类
    Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),new Class[] { Foo.class });

    //创建动态代理类的实例
    Foo foo = (Foo) proxyClass.getConstructor(new Class[] {InvocationHandler.class }). newInstance(new Object[] {handler });
  2. //创建InvocationHandler对象
    InvocationHandler handler = new MyInvocationHandler(...);

    //直接创建动态代理类的实例
    Foo foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] {Foo.class }, handler);

由Proxy类的静态方法创建的动态代理类具有以下特点:

  •   动态代理类是public、final和非抽象类型的;
  •   动态代理类继承了java.lang.reflect.Proxy类;
  •   动态代理类的名字以“$Proxy”开头;
  •   动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;


Proxy 类的isProxyClass(Class<?>cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;

动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。

由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
1. 假定变量foo 是一个动态代理类的实例,并且这个动态代理类实现了Foo 接口,那么“foo instanceof Foo”的值为true。把变量foo强制转换为Foo类型是合法的:
(Foo) foo //合法

2.每个动态代理类实例都和一个InvocationHandler 实例关联。Proxy类的getInvocationHandler(Objectproxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler 对象。

3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler对象的invoke()方法。

InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throwsThrowable

参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。
动态代理例程

 
 
 
java 使用动态代理 和ThreadLocal实现事务管理实例


以下信息来源于另一篇博客

Java设计模式-代理模式之静态代理

概念

为另一个对象提供一个替身或占位符以提供对这个对象的访问,使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理对象可以是远程的对象、创建开销大的对象或需要安全控制的对象

远程代理控制访问远程对象虚拟代理控制访问创建开销大的资源保护代理基于权限控制对资源的访问

看如下的类图:

 

仔细看上面的类图,首先是Subject它为RealSubject和Proxy提供了接口,通过实现同一个接口,Proxy在RealSubject出现的地方取代它,这点和适配器模式有比较大的区别。

RealSubject是真正做事情的对象,它被proxy代理控制访问的对象,Proxy持有RealSubject的引用,在某些例子中Proxy还会负责RealSubject对象的创建和销毁。客户和RealSubject的交互都必须通过Proxy。因为Proxy和RealSubject实现了相同的接口Subject,所以任何用到RealSubject的地方,都可以用Proxy代替。Proxy也控制了对RealSubject的访问,在某些情况下面,我们可能需要:权限保护,远程访问,创建开销控制。

 


代理模式分类

代理模式分为

静态代理

- 由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。上面的类图很好的表示了这种关系,

动态代理

- 在程序运行时运用反射机制动态创建而成。动态代理在代理ProxySubject和RealSubject之间增加了InvocationHandler这一层,这是一种通信间接化,增加了灵活性

一个关于静态代理的例子

警匪片大家一定都不会陌生,一些有钱的人看那个不顺眼,就想着找黑帮的帮忙杀人,黑帮就帮他们做一些坏事。这里的老板就变成了RealSubject,黑帮就变成了(Proxy),这里的real和proxy只是针对杀人是谁指使的(即幕后黑手是那个)

  • 首先定义一个共同的接口,使得RealSubject出现的地方Proxy都可以出现
package ProxyMode;
/*
* 抽象接口,对应类图中的Subject
*
*/
public interface Subject {
    public void SujectShow();
}
  • 然后定义一个RealSubject,真正的幕后黑手
package ProxyMode;

public class RealSubject implements Subject{

    @Override
    public void SujectShow() {
    // TODO Auto-generated method stub
        System.out.println("杀人是我指使的,我是幕后黑手!By---"+getClass());
    }
}
  • 然后定义一个代理类,黑帮,拿钱办事,但不是幕后黑手
package ProxyMode;

import proxy.RealeSubject;

public class ProxySubject implements Subject{

    private Subject realSubject;//代理类中有 老板的引用。

    public Subject TakeCall() //通过电话联系
    {
        return new RealSubject();
    }

    public void Before()
    {
        System.out.println("我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---"+getClass());
    }


    public void After()
    {
        System.out.println("正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---"+getClass());
    }

    @Override
    public void SujectShow() {
    // TODO Auto-generated method stub

        Object o=TakeCall(); //代理类接到了一个电话
        if(checked(o)) //检查这个电话是不是老板打过来的
        {
            Before();
            this.realSubject=(Subject)o;
            realSubject.SujectShow();
            After();
        }else {
            System.out.println("不好意思,你权限不够,我帮不了你!");
        }
    }

    boolean checked(Object o) //权限检查,这年头不是谁都可以冒充老板的
    {
        if(o instanceof RealSubject )
        return true;

        return false;
    }
}
  • 测试
package ProxyMode;

public class ProxyTest {

    public static void main(String[] args)
    {
        ProxySubject proxy=new ProxySubject();
        proxy.SujectShow();
    }
}

执行结果:

我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---class ProxyMode.ProxySubject
杀人是我指使的,我是幕后黑手!By---class ProxyMode.RealSubject
正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---class ProxyMode.ProxySubject

 

Java设计模式-代理模式之动态代理(附源码分析)

动态代理概念及类图

动态代理跟静态代理一个最大的区别就是:动态代理是在运行时刻动态的创建出代理类及其对象。上篇中的静态代理是在编译的时候就确定了代理类具体类型,如果有多个类需要代理,那么就得创建多个。还有一点,如果Subject中新增了一个方法,那么对应的实现接口的类中也要相应的实现这些方法。

动态代理的做法:在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。

类图如下所示:

上面类图中使用的JDK中的Proxy类,所以是需要要办法来告诉Proxy类需要做什么,不能像静态代理一样,将代码放到Proxy类中,因为现在Proxy不是直接实现的。既然这样的代码不能放在Proxy类中,那么就需要一个InvocationHandler,InvocationHandler的工作就是响应代理的任何调用。

 


动态代理实现过程

具体有如下四步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

一个具体的例子

接着上面的类图和静态代理中的例子,我们分别创建Subject和RealSubject

  • Subject
package ProxyMode;
/*
* 抽象接口,对应类图中的Subject
*
*/
public interface Subject {
    public void SujectShow();
}
  • RealSubject
package ProxyMode;

public class RealSubject implements Subject{
    @Override
    public void SujectShow() {
    // TODO Auto-generated method stub
    System.out.println("杀人是我指使的,我是幕后黑手!By---"+getClass());
    }
}
  • 建立InvocationHandler用来响应代理的任何调用
package ProxyMode;

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

public class SubjectProxyHandler implements InvocationHandler {

    private Object proxied;

    public SubjectProxyHandler( Object proxied ){
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("准备工作之前:");
        //转调具体目标对象的方法
        Object object= method.invoke( proxied, args);
        System.out.println("工作已经做完了!");
        return object;
    }
}
  • 动态代理类测试,这个代理类中再也不用实现Subject接口,可以动态的获得RealSubject接口中的方法
package ProxyMode;

import java.lang.reflect.Proxy;

public class DynamicProxy {
    public static void main( String args[] ){
        RealSubject real = new RealSubject();

        /*
            //一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
        Proxy.newProxyInstance(Subject.class.getClassLoader(),
            //一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态)
            new Class[]{Subject.class},
            //一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler
            new SubjectProxyHandler(real));
        */

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

        proxySubject.SujectShow();
    }
}
loader一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态)
handler一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler

 

  • 测试结果

准备工作之前:

杀人是我指使的,我是幕后黑手!By---class ProxyMode.RealSubject

工作已经做完了!

 

Proxy和InvocationHandler重要部分源码分析

java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

 

清单 1. Proxy 的静态方法

  • 方法 1: 该方法用于获取指定代理对象所关联的调用处理器,比如上面代码中的SubjectProxyHandler
static InvocationHandler getInvocationHandler(Object proxy)
  • 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
  •  方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
  •  方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)

 

下面重点看看newProxyInstance方法:

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {

    // 检查 h 不为 空,否则抛异常
    if (h == null) {
        throw new NullPointerException();
    }

    // 获得与制定类装载器和一组接口相关的代理类类型对象
    Class cl = getProxyClass(loader, interfaces);

    // 通过反射获取构造函数对象并生成代理类实例
    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());
    }
}

 

1、看这个方法的三个参数
public static Object newProxyInstance(ClassLoader loader, 
Class<?>[] interfaces, 
InvocationHandler h) throws IllegalArgumentException

 

loader一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态)
h一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler

从上面JDK源码中可以看出getProxyClass方法才是newProxyInstance方法中最重要的,该方法负责为一组接口动态地生成代理类类型对象。

2、下面开始解析proxy中的getProxyClass方法

该方法总共可以分为四个步骤:
对这组接口进行一定程度的安全检查,包括检查接口类对象是否对类装载器可见并且与类装载器所能识别的接口类对象是完全相同的,还会检查确保是 interface 类型而不是 class 类型。

这个步骤通过一个循环来完成,检查通过后将会得到一个包含所有接口名称的字符串数组,记为 String[] interfaceNames

for (int i = 0; i < interfaces.length; i++) {
    // 验证类加载程 序 解 析 该接口到同一类对象的名称。
    String interfaceName = interfaces[i].getName();
    Class<?> interfaceClass = null;
    try {
        interfaceClass = Class.forName(interfaceName, false, loader);
    } catch (ClassNotFoundException e) {
    }
    if (interfaceClass != interfaces[i]) {
        throw new IllegalArgumentException(interfaces[i] + " is not visible from class loader");
    }
    // 验证类对象真正代表一个接口
    if (!interfaceClass.isInterface()) {
        throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
    }
    //验证这个接口是不是重复的
    if (interfaceSet.contains(interfaceClass)) {
        throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
    }
    interfaceSet.add(interfaceClass); //interfaceset是一个hashset集合
    interfaceNames[i] = interfaceName;
}

3、从 loaderToCache 映射表中获取以类装载器对象为关键字所对应的缓存表,如果不存在就创建一个新的缓存表并更新到 loaderToCache。

缓存表是一个 HashMap 实例,正常情况下它将存放键值对(接口名字列表,动态生成的代理类的类对象引用)。当代理类正在被创建时它会临时保存(接口名字列表,pendingGenerationMarker)。标记 pendingGenerationMarke 的作用是通知后续的同类请求(接口数组相同且组内接口排列顺序也相同)代理类正在被创建,请保持等待直至创建完成。

synchronized (cache) {
    do {
    // 以接口名字列表作为关键字获得对应 cache 值
    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 跳出循环已进入创建过程
        break;
    } while (true);
}

4、动态创建代理类的类对象。
首先是确定代理类所在的包,其原则如前所述,如果都为 public 接口,则包名为空字符串表示顶层包;如果所有非 public 接口都在同一个包,则包名与这些接口的包名相同;如果有多个非 public 接口且不同包,则抛异常终止代理类的生成。确定了包后,就开始生成代理类的类名,同样如前所述按格式“$ProxyN”生成。

// 动态地生成代 理类的字节码数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
try {
    // 动态地定义新生成的代理类
    proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0,
    proxyClassFile.length);
} catch (ClassFormatError e) {
    throw new IllegalArgumentException(e.toString());
}
// 把生成的代理类的类对象记录进 proxyClasses 表
proxyClasses.put(proxyClass, null);

到了这里,其实generateProxyClass方法也是一个重点,但是generateProxyClass的方法代码跟踪不了,位于并未公开的 sun.misc 包,有若干常量、变量和方法以完成这个神奇的代码生成的过程,但是 sun 并没有提供源代码以供研读
结尾部分
根据结果更新缓存表,如果成功则将代理类的类对象引用更新进缓存表,否则清楚缓存表中对应关键值,最后唤醒所有可能的正在等待的线程。

synchronized (cache) {
    if (proxyClass != null) {
        cache.put(key, new WeakReference<Class<?>>(proxyClass));
    } else {
        cache.remove(key);
    }
    cache.notifyAll();
}

java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
InvocationHandler 的核心方法,我们最关心的是Invoke方法为什么会被调用,见下面分析:

Object invoke(Object proxy, Method method, Object[] args)

// 该方法负责集中处理动态代理类上的所 有方法调用。
//第一个参数既是代理类实例,
//第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行

每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 newProxyInstance 的第三个参数)。
很多人肯定跟我一样,我们在Handler中调用的method.invoke方法中并没有显示的调用invoke方法,只是在newProxyInstance中应用了一个handler对象,有了上面关于newProxyInstance的源码分析,我们知道了 newproxyinstance生成了一个$Proxy0类代理。当调用Subjectshow()方法时,其实调用的$Proxy0的SubjectShow()方法,从而调用父类Proxy中传进来第三个参数(h)的的Invoke方法。

//这个方法是 Proxy源码中的
protected Proxy(InvocationHandler h) {
    this.h = h;
}

来看NewProxyInstance方法生成的$Proxy0代理类的源码

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m2;

    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("***.RealSubject").getMethod("request",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());
        }
    } //static

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

    @Override
    public final boolean equals(Object obj) {
        try {
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final int hashCode() {
        try {
            return ((Integer) super.h.invoke(this, m0, null)).intValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void SubjectShow() {
        try {
            super.h.invoke(this, m3, null); //就是这个地方 调用h.invoke()
            return;
        } catch (Error e) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final String toString() {
        try {
            return (String) super.h.invoke(this, m2, null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

从上面的$Proxy0中找到方法SubjectSHow()方法,我们可以看到中间调用了父类Proxy的参数Handler h的invoke方法,也就调用了ProxyHandler中的invoke()方法,还可以看到¥Proxy0还代理了equals()、hashcode()、tostring()这三个方法,至此动态代理实现机制就很清楚了

 

Keil5编译报错:ARM Compiler Version 5缺失的完整解决方案 本文提供了Keil5编译报错“ARM Compiler Version 5缺失”的完整解决方案。详细介绍了手动安装ARM Compiler Version 5的步骤,包括下载安装包、配置编译器路径及常见问题排查,帮助开发者快速恢复老项目的编译环境。 阅读详情

相关推荐

KiCad 7.0 + 嘉立创打样:从原理图到实物,打造你的双LLCC68 LoRa串口透传板

本文详细介绍了使用KiCad 7.0设计双LLCC68 LoRa串口透传板的完整流程,从原理图设计到嘉立创打样。重点解析了AVR+LLCC68组合的优势、双模块布局的电磁兼容设计、SPI接口配置及射频走线技巧,并提供了实测数据和常见问题解决方案,帮助开发者高效实现物联网设备的低功耗远距离通信。

weixin_28693447的博客 260

DNS的方式以及方法

named查询使用的是UDP协议和端口53。响应通过UDP返回,除非他们大于512K,这种情况使用TCP。服务器之间的“区传送”则都使用TCP。 委托:所有的名字服务器都知道根服务器。而根服务器又都知道gTLD,顺着这条链进一步往下,edu知道fudan.edu,com知道china.com…依次类推。实例:假设我希望从机器marco.comp.fudan.edu查询机器cs.military.c...

wx25051的博客 1841

微信小程序导航栏滑动一定距离后固定到顶部

接上一篇文章的内容,通常在一个页面中部会有一个导航栏查看不同的内容,这篇文章旨在实现在页面下滑的过程中导航栏自动固定到顶部以便我们阅读过程中的切换。 下滑一段距离后自动固定到顶部 首先,思考这个功能应该是怎么实现的: 在页面下滑的过程中,我们希望系统应当能识别下滑了多少距离,当原本的导航栏逐渐被遮住以后(遮住意味着下滑了特定距离),触发这个功能,执行另一种样式,将导航栏固定在页面顶端,同时如果我们将页面往上滑,系统能识别到原来的导航栏能露出来了(即距离顶端的高度小于一个特定的值),这时候又执行最初的样式

Oblivision_Geek的博客 4032

代理模式(静态代理、动态代理)

代理模式 静态代理 静态代理角色分析 抽象角色 : 一般使用接口或者抽象类来实现(会被真是角色和代理角色所继承) 真实角色 : 被代理的角色 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 . 客户 : 使用代理角色来进行一些操作 . 代码实现 Rent . java 即抽象角色 package com.wlw.proxy; // 抽象角色:租房, 房东与代理都要实现这个接口去完成租房功能 public interface Rent { void

wang_luwei的博客 861

概述DeepLab系列(deeplab v1, deeplab v2, deeplab v3, deeplab v3+)

前言:图像分割是指像素级别的图像识别,即标注出图像中每个像素所属的对象类别。 语义分割更注重类别之间的区分,而实例分割更注重个体之间的区别。 DeepLab是由Google团队提出的一系列图像分割算法。 DeepLab v1 (2014年) Paper (ICLR 2015) Code 创新点: 空洞卷积(Atrous Conv); <解决编码过程中信号不断被下采样,细节丢失的问题> 全连接条件随机场(Fully-connected Conditional Random Field)。

ZSH12345678900的博客 5528

基于 LSTM 的船舶轨迹预测,单步预测

基于 LSTM 的船舶轨迹预测,单步预测

fyuhao的博客 1万+

静态代理模式(StaticProxy)

静态代理模式(StaticProxy) 真实的对象和代理对象都要实现同一个接口 代理对象呀是真实的角色 优点: 1.代理对象可以做很多真实对象做不了的事情 2.真实对象专注做自己的事情 interface Marry { void HappyMarry(); }` 真实角色 class You implements Merry{ @Override public void HappyMerry() { System.out.println("You 结婚");

凌霄 862

信息奥赛课课通(C++)p154-1近似排序

试题描述 读入一对正整数,将这两个数之间(包括这两个数本身)的所有数按下述特别规则排序后输出,该特别规则是按两数倒过来的值进行比较决定其大小,如30倒过来为3,29倒过来为92,则29大于30. 输入要求 1行,包含两个用空格隔开的自然数,这两个自然数给出了待排序数的范围,其中1≤第一个数≤第二个数≤999999999,两个数之差不超过100. 输出要求 输出排序后的数据,每行输出...

mengdicfm的博客 7283

代理模式(Proxy):静态代理(Static Proxy)、动态代理(Dynamic Proxy)和CGLIB代理

一、代理模式 为其他对象提供一种代理以控制对这个对象的访问。 二、代理模式结构图 三、静态代理 这种代理方式需要代理对象和目标对象实现一样的接口。 1、优点: 可以在不修改目标对象的前提下扩展目标对象的功能。 2、缺点: 冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。不易维:一旦接口增加方法,目标对象与代理对象都要进行修改。 3、代码实现: //被追女孩子类 public c...

码农峰酱 1967

Ubuntu开机卡在BusyBox?3种方法快速修复initramfs错误(附详细命令)

本文详细介绍了Ubuntu开机卡在BusyBox并出现initramfs错误的3种修复方法,包括使用fsck检查文件系统、调整BIOS/UEFI存储设置以及修改GRUB内核参数。针对常见的文件系统错误和根设备无法找到问题,提供了具体的命令行操作步骤和实用技巧,帮助用户快速恢复系统启动。

milk8的博客 785

手把手复现论文:SVPWM过调制I区与II区算法仿真(附MATLAB源码)

本文详细介绍了SVPWM过调制I区与II区算法的MATLAB仿真实现,从理论推导到Simulink建模逐步解析。通过源码示例展示幅值补偿和六边形跟踪等关键技术,帮助电力电子研究者掌握过调制算法的核心实现方法,适用于电机控制、变频器等工业应用场景。

weixin_28739079的博客 530

dao接口有什么好处_静态代理和动态代理有什么区别?--乐字节java

代理模式代理模式在 Java 开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。如租房的例子:房客、中介、房东。对应于代理模式中即:客户类、代理类 、委托类(被代理类)。为某一个对象(委托类)提供一个代理(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配...

weixin_39711914的博客 151

GPU 运维实战:H100/H800/B300 换卡与压测

(烧多久、看什么、什么算合格)。文末还给了一个能直接跑的验收判定脚本,三个真实场景的裁决输出都在。

老韩的Linux云计算架构师进阶之路 271

彻底搞懂动态代理

生活中我们肯定知道代理商的概念,代理商代替厂家售卖其生产的商品,厂家“委托”代理商为其销售商品。通过代理商这种销售模式,普通消费者是不直接跟厂家打交道,但是却能获得厂家的商品服务,也就是说,“委托者”对普通消费者来说是不可见的。其次,同一厂家的不同代理商,可以针对自身的情况做一些个性化的营销策略,消费者通过代理商获取不同的服务,但代理商并没有改变厂家的任何策略。我们把代理商和厂家进行抽象,前者可抽...

卓立的博客 602

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Spring framework Day17:JDK和CGLIB动态代理

动态代理是一种在运行时动态生成代理类的技术,它可以在不修改目标类代码的情况下为目标类提供代理功能,从而在被代理对象的方法执行前后添加额外的逻辑。动态代理主要由两个部分组成:代理工厂和回调处理器。代理工厂用于生成代理对象,通常使用类来实现。回调处理器则用于拦截对代理对象方法的调用,并实现增强逻辑。常见的回调处理器有接口、接口等。在调用代理对象的方法时,代理对象会将方法调用请求转发给回调处理器,并在回调处理器中执行增强逻辑。相比于静态代理,动态代理的优势在于可以动态地生成代理类,具有更好的灵活性和可扩展性。

zhiqiuqiu2的博客 811

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

动态代理详解

代理模式通过引入一个代理对象来控制对原对象的访问。代理对象在客户端和目标对象之间充当中介,负责将客户端的请求转发给目标对象,同时可以在转发请求前后进行额外的处理。转化为生活中例子来讲(代购/秘书等),我们需要购买一个物品时,自己又不想动,就在网上找了一个代购的小姐姐帮忙购买,这样即拿到了商品,自己本身并没有做什么事情,可以看作是一个代理,即 将自己的权利交给其他人/秘书来做的情况,就是代理模式的一种。代理模式分为静态代理,与动态代理两种模式,我们就展开来讲讲这两种模式的区别。

2401_85207246的博客 1377

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

利用代码分别实现jdk动态代理和cglib动态代理_代理模式

代理模式分为静态代理和动态代理,其中动态代理又分为JDK动态代理和CGLIB动态代理代理模式的三个要素:A、抽象的类或者接口 —— 完成一件怎样的事情B、被代理对象 —— 事情操作具体内容C、代理对象 —— 帮助我们完成事情的同时还可以增加其他的功能为了便于理解写了个具体的例子: 我们找中介租房子A、抽象的类或者接口 —— 租房子B、被代理对象 —— 房东C、代理对象 —— 中介代理模式的好处:A...

weixin_39946657的博客 93

静态代理和动态代理

首先我们应该知道,代理模式,要有【角色1】一个真实的人(目的,要租房子)【角色2】:要有代理,带着你找房子,会更简单,便捷,即中介,【角色3】:要有出租房子的人,即房东,【角色4】:是一个抽象角色,中介和房东都有一个共同的目的,将房子出租4个角色关系如图所示。

2301_78170274的博客 204

Java动态代理学习

一、动态代理VS静态代理静态代理:就是程序运行前就已经存在的编译好的代理类。设计模式中的代理模式编写的代理类即为静态代理。 动态代理:代理类程序运行前并不存在,需要在程序运行时动态生成(无需手工编写代理类源码),那就是今天要说的动态代理了。根据Java的反射机制动态生成。二、动态代理标准实现流程1、实现目标接口public interface TargetInterface { pub

storm1314888的专栏 285

动态代理和静态代理

1 代理Proxy概念 Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题 ​ 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而

皮卡丘的情绪 556

动态代理和静态代理的区别_静态代理和动态代理

一:什么是代理模式1.定义:为其他对象提供一种代理以控制对这个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。2.例子:最开始接触JDBC操作数据库的时候,业务层每一个方法都需要做以下几件事(1)打开数据库连接(2)执行我们想要的操作(3)关闭数据库连接此时,我的核心业务是第(2)步,其余两步为辅助业务。当核心业务与辅助业务写在了一个方法中时。会...

weixin_39941732的博客 5715

静态代理和动态代理的区别

静态代理和动态代理的区别 按照代理的创建时期,代理类可以分为两种: 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 动态:在程序运行时运用反射机制动态创建而成。 静态代理类优缺点 优点: 代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合),对于如上的客户端代码,newUserManagerImpl()可以应用工厂将它隐藏。 缺点: 1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大

亦疏爱吃肉 3258

静态代理和动态代理的区别,使用场景是什么

代理模式 (1)什么是代理? 代理是一种常用的设计模式,主要作用是为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以再客户端和目标对象之间起到中介的作用. (2)什么时候使用代理? 设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的diamante,里面代码逻辑让人摸不到头脑,这是就会很难...

weixin_43666051的博客 3008

静态代理、JDK动态代理、CGLIB动态代理以及JDK和CGLIB动态代理的区别

代理模式在 Java 开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。如租房的例子: 房客、中介、房东。对应于代理模式中即:客户类、代理类 、委托类 (被代理类)为某一个对象(委托类)提供一个代理 (代理类),用来控制对这个对象的访问。委托类和代理类有个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象。//目标对象//通过构造器传入目标对象/*** 获取代理对象* @return*/

来都来了 1139

静态代理和动态代理的区别和联系

静态代理和动态代理的区别和联系 代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。 为了保...

absolute_chen的博客 4049
上一篇: 正则表达式基础知识
下一篇: IntelliJ 创建main函数快捷方式
Marvin-Fox
博客等级 码龄11年 190粉丝 100原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值