精华内容
下载资源
问答
  • 2018-07-22 10:53:46

    一、概念

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

    静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
    动态代理类:在程序运行时,运用反射机制动态创建而成。

    静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
    静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
    动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。

    还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。

    二、静态代理类

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

    package com.sheting.reflect.proxy.staticproxy;
    
    import java.util.Date;
    
    /**
     * created by zheTing on 2018-03-06 12:46
     */
    public interface HelloService {
    
        String echo(String msg);
    
        Date getTime();
    }
    
    package com.sheting.reflect.proxy.staticproxy;
    
    import java.util.Date;
    
    /**
     * created by zheTing on 2018-03-06 12:47
     */
    public class HelloServiceImpl implements HelloService {
        @Override
        public String echo(String msg) {
            return "echo:" + msg;
        }
    
        @Override
        public Date getTime() {
            return new Date();
        }
    }
    package com.sheting.reflect.proxy.staticproxy;
    
    import java.util.Date;
    
    /**
     * created by zheTing on 2018-03-06 12:48
     */
    public class HelloServiceProxy implements HelloService {
        //表示被代理的HelloService 实例
        private HelloService helloService;
    
        public HelloServiceProxy(HelloService helloService) {
            this.helloService = helloService;
        }
    
        public void setHelloServiceProxy(HelloService helloService) {
            this.helloService = helloService;
        }
    
        @Override
        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;
        }
    
        @Override
        public Date getTime() {
            //预处理
            System.out.println("before calling getTime()");
            //调用被代理的HelloService 实例的getTime()方法
            Date date = helloService.getTime();
            //事后处理
            System.out.println("after calling getTime()");
            return date;
        }
    }
    package com.sheting.reflect.proxy.staticproxy;
    
    /**
     * created by zheTing on 2018-03-06 12:49
     */
    public class Test {
        public static void main(String args[]) {
            HelloService helloService = new HelloServiceImpl();
            HelloService helloServiceProxy = new HelloServiceProxy(helloService);
            System.out.println(helloServiceProxy.echo("hello"));
        }
    }

    三、动态代理类

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

    具体例子参考:https://blog.csdn.net/tb9125256/article/details/81152684

    更多相关内容
  • 带扫登录的网页登录静态页面html模板
  • 22-8位数静态显示其中之二(51单片机C语言实例Proteus仿真代码)22-8位数静态显示其中之二(51单片机C语言实例Proteus仿真代码)22-8位数静态显示其中之二(51单片机C语言实例Proteus仿真代码)22-8位数...
  • 全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。 - 程序结束后系统释放 文字常量区 —...
  • html+js生成条形码和二维码 纯静态同时生成条形码和二维码
  • 有静态和动态分析以及功能签名查找的以太坊evm字节反汇编程序 [ ] [ ] 反汇编evm字节 将合同反编译为伪代码 安装 点子 #> pip3 install "ethereum-dasm[mythril,abidecoder]" #> python3 -m ethereum_dasm -...
  • 代理模式是常用的Java设计模式,它的特征是代理类与委托类同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类...

     

    一、概念

      代理模式是常用的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()这三个方法,至此动态代理实现机制就很清楚了

     

    展开全文
  • 静态显示:6位数管循环显示数字0~F; 动态态显示:6位数管同时显示数字1~6; 源码以及proteus电路原理图
  • 静态ram和动态ram的区别什么

    千次阅读 2020-12-22 06:58:32
    静态ram和动态ram的区别 静态RAM(SRAM)速度非常快,只要电源存在内容就不会自动消失。其基本存储电路为6个MOS管组成1位,因此集成度相对较低,功耗也较大。一般高速缓冲存储器用它组成。 动态RAM(DRAM)的内容在...

    随机存取存储器(random access memory,RAM)又称作“随机存储器”,是与CPU直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。

    存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。 按照存储单元的工作原理,随机存储器又分为静态随机存储器(英文:Static RAM,SRAM)和动态随机存储器(英文Dynamic RAM,DRAM)。

    什么是静态RAM

    存储器是计算机的记忆部件。CPU 要执行的程序、要处理的数据、处理的中间结果等都存放在存储器中。

    目前微机的存储器几乎全部采用半导体存储器。存储容量和存取时间是存储器的两项重要指标,它们反映了存储记忆信息的多少与工作速度的快慢。半导体存储器根据应用可分为读写存储器(RAM)和只读存储器(ROM)两大类。

    读写存储器(RAM)

    读写存储器又称随机存取存储器(Random Access Memory)简称RAM,它能够在存储器中任意指定的地方随时写入或读出信息;当电源掉电时,RAM 里的内容即消失。根据存储单元的工作原理,RAM 又分为静态RAM 和动态RAM。静态RAM 用触发器作为存储单元存放1 和0,存取速度快,只要不掉电即可持续保持内容不变。一般静态RAM 的集成度较低,成本较高。

    动态RAM 的基本存储电路为带驱动晶体管的电容。电容上有无电荷状态被视为逻辑1 和0。随着时间的推移,电容上的电荷会逐渐减少,为保持其内容必须周期性地对其进行刷新(对电容充电)以维持其中所存的数据,所以在硬件系统中也得设置相应的刷新电路来完成动态RAM 的刷新,这样一来无疑增加了硬件系统的复杂程度,因此在单片机应用系统中一般不使用动态RAM。

    静态RAM 的基本存储电路为触发器,每个触发器存放一位二进制信息,由若干个触发器组成一个存储单元,再由若干存储单元组成存储器矩阵,加上地址译码器和读/写控制电路就组成静态RAM。与动态RAM 相比,静态RAM 无须考虑保持数据而设置的

    刷新电路,故扩展电路较简单。但由于静态RAM 是通过有源电路来保持存储器中的数据,因此,要消耗较多功率,价格也较高。

    RAM 内容的存取是以字节为单位的,为了区别各个不同的字节,将每个字节的存储单元赋予一4个编号,该编号就称为这个存储单元的地址,存储单元是存储的最基本单位,不同的单元有不同的地址。在进行读写操作时,可以按照地址访问某个单—元。

    由于集成度的限制,目前单片RAM 容量很有限,对于一个大容量的存储系统,往往需要若干RAM 组成,而读/写操作时,通常仅操作其中一片(或几片),这就存在一个片选问题。RAM 芯片上特设了一条片选信号线,在片选信号线上加入有效电平,芯片即被选中,可进行读/写操作,末被选中的芯片不工作。片选信号仅解决芯片是否工作的问题,而芯片执行读还是写则还需有一根读写信号线,所以芯片上必须设读/写控制线。

    下面是几种常用静态RAM:

    在8031 单片机应用系统中,最常用的静态数据存储器RAM 芯片有6116(2Kx8)和6264(8Kx8)两种。

    什么是动态RAM

    在动态RAM芯片内部,每个内存单元保存一位信息。单元由下面两部分组成:一个晶体管和一个电容器。当然这些部件都非常地小,因此一个内存芯片内可以包含数百万个。电容器保存信息位——0或1(有关位的信息,请参见位和字节)。

    晶体管起到了开关的作用,能让内存芯片上的控制线路读取电容上的数据,或改变其状态。电容器就像一个储存电子的小桶。在存储单元中写入1,小桶内就充满电子;写入0,小桶就被清空。这只“桶”的问题在于:它会泄漏。只需大约几毫秒的时间,一个充满电子的小桶就会漏得一干二净。因此,为了确保动态存储器能正常工作,必须由CPU或是由内存控制器对所有电容不断地进行充电,使它们在电子流失殆尽之前保持“1”值。

    为此,内存控制器会先行读取存储器中的数据,再把数据写回去。这种刷新操作每秒钟会自动进行数千次。动态RAM正是得名于这种刷新操作。它需要不间断地进行刷新,否则就会丢失所保存的数据。这一刷新动作的缺点就是费时,并且会降低内存速度。静态RAM使用了截然相反的技术。静态RAM用某种形式的触发器来保存内存的每个位(有关触发器的详细信息,请参阅布尔逻辑的应用)。

    内存单元的触发器由4个或6个晶体管以及一些线路组成,但从来不需要刷新。这使得静态RAM比动态RAM要快得多。但是,由于它所含的部件较多,静态内存单元在芯片上占用的空间会远远超过动态内存单元,使得每个芯片上的内存较小。

    静态ram和动态ram的区别

    静态RAM(SRAM)速度非常快,只要电源存在内容就不会自动消失。其基本存储电路为6个MOS管组成1位,因此集成度相对较低,功耗也较大。一般高速缓冲存储器用它组成。

    动态RAM(DRAM)的内容在10-3或l0-6秒之后自动消失,因此必须周期性的在内容消失之前进行刷新。由于它的基本存储电路由一个晶体管及一个电容组成,因此它的集成度高,成本较低,另外耗电也少,但它需要一个额外的刷新电路。DRAM运行速度较慢,SRAM比DRAM要快2~5倍,一般,PC机的标准存储器都采用DRAM组成。

    打开APP阅读更多精彩内容

    点击阅读全文

    展开全文
  • 透明LED显示屏驱动方式有静态扫描和动态扫描两种,静态扫描又叫扫描驱动。下面具体来看看这两种扫描方式的特点及区别: 扫描方式:在一定的显示区域内,同时点亮的行数与整个区域行数的比例。 1、动态扫描:动态扫描...

    透明LED显示屏驱动方式有静态扫描和动态扫描两种,静态扫描又叫扫描驱动。下面具体来看看这两种扫描方式的特点及区别:

    扫描方式:在一定的显示区域内,同时点亮的行数与整个区域行数的比例。

    在这里插入图片描述

    1、动态扫描:动态扫描是从驱动IC的输出到像素点之间实行“点对列”的控制,动态扫描需要控制电路,成本要低,显示效果差一些,亮度损失较大,亮度偏低,适用于室内环境显示,比如室内橱窗门店。

    2、静态扫描:静态扫描是从驱动IC的输出到像素点之间实行“点对点”的控制,静态扫描不需要控制电路,成本要高,但显示效果好,稳定性好,亮度损失较小,显示屏亮度高,适用于室外显示环境,比如户外玻璃幕墙。

    透明LED显示屏扫描模式

    1/1扫描:这属于亮度更高的驱动方式,只在户外使用,它们的控制方式也是由此类推。

    1/2扫描:其他情况相同的条件下,1/2扫描显示屏亮度低于静态,适用于户外和半户外。它的控制方式是相当于本来给单灯供电的电流同时供给了两个LED灯。所以它在亮度上会有所降低。当然在同时供给两个LED灯电流时不是平均的分配电流,而是电流不断地在两LED间扫描,其扫描频率达到了每秒钟100次,也就是说电流在1/100秒内是供个其中一个LED,在下一1/100秒内是供给了另一个LED。其实这两个LED是在不断的亮灭,只是人眼的视觉暂留效果让我们察觉不到它们在不断的亮灭,只要扫描频率达到了每秒64次以上,人眼就分辨不出来了。

    在这里插入图片描述

    1/4扫描:在其他条件相同的情况下,1/4扫描的显示屏只有1/2扫描的显示屏一半亮度,适用于半户外和户内。其控制方式就是从1/2的两个LED增加到了4个LED。电流在4个LED间扫描。

    1/8扫描,1/10扫描:这些属于亮度更低的驱动方式了,一般只在户内使用。它们的控制方式也是由此类推。

    展开全文
  • 电子政务-一种静态二维码和动态条形复合防伪电子标签.zip
  • 文章目录动态和静态静态库与动态库的概念理解动静态库如何打包动静态库与如何使用动静态库如何制作打包动态库 为什么我们要使用别人(一般是顶尖的工程师写的)的代码? 为了开发效率鲁棒性(健壮性) 如何使用...
  • 代理类委托类共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。 代理模式是经典设计...
  • 【实验12】4位数管十位静态显示.zip源码arduino例程源码GL9例程源代码【实验12】4位数管十位静态显示.zip源码arduino例程源码GL9例程源代码【实验12】4位数管十位静态显示.zip源码arduino例程源码GL9例程源...
  • Capacita编程语言 Capacita是一种同时具有静态类型模式和动态类型模式的语言。 它将提供类型合并,并且当前可编译为虚拟字节
  • 动态ip和静态ip的区别

    千次阅读 2019-01-10 08:41:27
    对于基于TCP/IP协议的局域网,IP地址的管理方式主要有静态分配方式和动态分配方式,还可以根据需要将两种方式结合使用,即混合分配方式。  1.动态IP上网,又叫做DHCP上网  自动获取IP上网。动态IP这种上网方式...
  •  图1 数码管段分布及显示示例 按照工作方式, 数码管驱动可以分为和动态扫描。所谓静态显示, 就是每一个数码管的段码都要独占具有锁存功能的输出口, CPU把要显示的字码送到输出口上,就可以使数码管显示对应的字符...
  • 有什么区别?先说总结目标文件二、什么静态库?什么动态库?有什么区别?三、为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明的函数呢?动静态区别1.可执行文件大小不一样2.占用...
  • 数码管是显示屏其中一类, 通过对其不同的管脚输入相对的电流...8位数静态显示程序静态显示8位数管中任意一位------------------------------------------------*/#include#define DataPort P0 //定义数据端口...
  • 一个Java 程序要经过编写、编译、运行三个步骤,其中编写代码不在我们讨论的范围之内,那么我们的重点自然就放在了编译 运行这两个阶段,由于编译运行阶段过程相当繁琐,下面就我的理解来进行解释:Java程序从...
  • 文章目录动静态库动静态库的概念动态链接的特点静态链接的特点查看文件的动静态链接属性动态链接的机理生成&&使用静态库生成&&使用动态库使用外部库 动静态库的概念 静态库(.a):程序在编译链接...
  • 仿淘宝网、阿里云登录界面的静态界面,采用密码输入切换登录方式,模板内涵CSS,使用jquery方式实现切换,纯粹的切换界面。
  • Linux动态和静态

    万次阅读 多人点赞 2021-10-28 10:56:35
    文章目录动静态库的基本原理认识动静态库动静态库各自的特征静态库的打包与使用打包使用动态库的打包与使用打包使用 动静态库的基本原理 动静态库的本质是可执行程序的“半成品”。 我们都知道,一堆源文件...
  • 静态数码管和动态数码管

    千次阅读 多人点赞 2020-06-09 10:51:51
    目录一,什么是数码管二,静态数码管的驱动三,动态数码管四,动态数码管显示编程实战五,使用38译码器驱动动态数码管 一,什么是数码管 1、数码管 (1)作用:数码管是显示器件,用来显示数字的 (2)分类:单个(1位...
  •  JSP页面第一次被请求时,会被JSP引擎转译成Servlet的Java文件,然后再被编译成字节文件执行。JSP指令标记为JSP页面转译提供整个页面的相关信息。  include指令用于在JSP页面静态插入一个文件,被插入的文件可以...
  • 代理模式 (1)什么是代理? 代理是一种常用的设计模式,主要作用...设计模式中一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的diamante,里面代码逻辑让人摸不到头脑,这是就会很难...
  • 行业分类-设备装置-保护Java字节代码免受恶意运行环境中的静态和动态攻击的系统方法.zip
  • 静态类型和动态类型的区别编译型语言解释型语言混合型语言静态类型语言动态类型语言 编译型语言 源代码需要通过编译器编译成机器可识别的机器,包括编译链接两个过程。不同操作系统下的可执行文件不一样。代表...
  • 静态链接与动态链接的区别和使用

    万次阅读 多人点赞 2018-11-27 13:34:59
     静态链接:譬如让书本白板上的笔记之间做静态链接,就是把白板上的笔记抄在书上书笔记形成一个整体(可执行程序),这个时候把白板上的内容擦掉也没关系,因为已经整合到书上了。静态链接的优点是“效率高”...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 596,712
精华内容 238,684
关键字:

动态码和静态码有什么区别