精华内容
下载资源
问答
  • Java实现动态代理的两种方式。 相对来说cglib更加方便。可以实现为实现接口的类(非final类)
  • 在使用Java动态代理时出现了一个很棘手的问题,实现类里抛出了一个自定义异常,但外面捕获不到。  虽然使用 printStack 可以输出调试信息,但通过 getMessage 获取不到提示,因为项目需求是捕捉到同一种自定义异常...
  • Java动态代理,包括JDK自带的和cglib所集成的。
  • Java动态代理实现数据源连接池,用代理类实现的连接池代码,绝对完整的案例,下载源码就能跑起来!Java动态代理实现数据源连接池,用代理类实现的连接池代码
  • 本文通过分析Java动态代理的机制和特点,解读动态代理类的源代码,并且模拟推演了动态代理类的可能实现,向读者阐述了一个完整的 Java动态代理运作过程,希望能帮助读者加深对Java动态代理的理解和应用。本文的标签...
  • 一个简单的java动态代理的实例
  • Java动态代理内存中生成的$Proxy0类
  • 什么是Java动态代理,如何实现一个动态代理例子

    千次阅读 多人点赞 2019-09-04 11:06:15
    Java动态代理 一、概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说...

    Java动态代理

    一、概述

    1. 什么是代理

    我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使用代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来:

    优点一:可以隐藏委托类的实现;

    优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

    2. 静态代理

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。 下面我们用Vendor类代表生产厂家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现,委托类和代理类都实现了Sell接口,Sell接口的定义如下:

    /**
     * 委托类和代理类都实现了Sell接口
     */
    public interface Sell { 
        void sell(); 
        void ad(); 
    } 
    复制代码

    Vendor类的定义如下:

    /**
     * 生产厂家
     */
    public class Vendor implements Sell { 
        public void sell() { 
            System.out.println("In sell method"); 
        } 
        
        public void ad() { 
            System,out.println("ad method");
        }
    } 
    复制代码

    代理类BusinessAgent的定义如下:

    /**
     * 代理类
     */
    public class BusinessAgent implements Sell {
        private Sell vendor;
        
        public BusinessAgent(Sell vendor){
            this.vendor = vendor;
        }
    
        public void sell() { 
            vendor.sell();
        } 
        
        public void ad() {
            vendor.ad();
        }
    } 
    复制代码

    从BusinessAgent类的定义我们可以了解到,静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。

    下面我们考虑一下这个需求:给Vendor类增加一个过滤功能,只卖货给大学生。通过静态代理,我们无需修改Vendor类的代码就可以实现,只需在BusinessAgent类中的sell方法中添加一个判断即可如下所示:

    /**
     * 代理类
     */
    public class BusinessAgent(){ implements Sell {
        private Sell vendor;
        
        public BusinessAgent(Sell vendor){
            this.vendor = vendor;
        }
    
        public void sell() {
            if (isCollegeStudent()) {
                vendor.sell();
            }
        } 
        
        public void ad() {
            vendor.ad();
        }
    } 
    复制代码

    这对应着我们上面提到的使用代理的第二个优点:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。静态代理的局限在于运行前必须编写好代理类,下面我们重点来介绍下运行时生成代理类的动态代理方式。

    二、动态代理

    1. 什么是动态代理

    代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。 这么说比较抽象,下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。

    现在,假设我们要实现这样一个需求:在执行委托类中的方法之前输出“before”,在执行完毕后输出“after”。我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类来进行介绍。首先我们来使用静态代理来实现这一需求,相关代码如下:

    public class BusinessAgent implements Sell {
        private Vendor mVendor; 
     
        public BusinessAgent(Vendor vendor) {
            this.mVendor = vendor; 
        } 
     
        public void sell() {
            System.out.println("before"); 
            mVendor.sell(); 
            System.out.println("after"); 
        } 
     
        public void ad() {
            System.out.println("before"); 
            mVendor.ad(); 
            System.out.println("after"); 
        }
    } 
    复制代码

    从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。下面我们来具体介绍下如何使用动态代理方式实现我们的需求。

    2. 使用动态代理

    2.1 InvocationHandler接口

    在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:

    /**
     * 调用处理程序
     */
    public interface InvocationHandler { 
        Object invoke(Object proxy, Method method, Object[] args); 
    } 
    复制代码

    从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。下面我们来一步一步具体实现它。

    2.2 委托类的定义

    动态代理方式下,要求委托类必须实现某个接口,这里我们实现的是Sell接口。委托类Vendor类的定义如下:

    public class Vendor implements Sell { 
        public void sell() { 
            System.out.println("In sell method"); 
        }
    
        public void ad() {
            System,out.println("ad method");
        }
    } 
    复制代码

    2.3中介类

    上面我们提到过,中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下:

    public class DynamicProxy implements InvocationHandler { 
        //obj为委托类对象; 
        private Object obj; 
     
        public DynamicProxy(Object obj) {
            this.obj = obj;
        } 
     
        @Override 
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
            System.out.println("before"); 
            Object result = method.invoke(obj, args); 
            System.out.println("after"); 
            return result; 
        }
    } 
    复制代码

    从以上代码中我们可以看到,中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法,看到这里是不是觉得似曾相识?

    通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗?

    实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;

    代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。

    也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。

    2.4动态生成代理类

    动态生成代理类的相关代码如下:

    public class Main { 
        public static void main(String[] args) {
            //创建中介类实例 
            DynamicProxy inter = new DynamicProxy(new Vendor()); 
            //加上这句将会产生一个$Proxy0.class文件,这个文件即为动态生成的代理类文件
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 
    
            //获取代理类实例sell 
            Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter)); 
     
            //通过代理类对象调用代理类方法,实际上会转到invoke方法调用 
            sell.sell(); 
            sell.ad(); 
        }
    } 
    复制代码

    在以上代码中,我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。这个方法的声明如下:

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

    方法的三个参数含义分别如下:

    loader:定义了代理类的ClassLoder; interfaces:代理类实现的接口列表 h:调用处理器,也就是我们上面定义的实现了InvocationHandler接口的类实例

    我们运行一下,看看我们的动态代理是否能正常工作。我这里运行后的输出为

     

    image

     

     

    说明我们的动态代理确实奏效了。

    上面我们已经简单提到过动态代理的原理,这里再简单的总结下:首先通过newProxyInstance方法获取代理类实例,而后我们便可以通过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法,在invoke方法中我们调用委托类的相应方法,并且可以添加自己的处理逻辑。

    三、代理模式

    这个应该是设计模式中最简单的一个了,类图

    image

     

     

    代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调用实际对象的操作

    Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理,这样说的比较笼统,举个简单的例子

    比如我们在应用中有这样一个需求,在对某个类的一个方法的调用前和调用后都要做一下日志操作,

    一个普通的接口

    public interface AppService {  
        public boolean createApp(String name);  
    }  
    复制代码

    该接口的默认实现类

    public class AppServiceImpl implements AppService {  
        public boolean createApp(String name) {  
            System.out.println("App["+name+"] has been created.");  
            return true;  
        }  
    }
    复制代码

    日志处理器(实质充当了中介类)

    /**
     * 注意需实现Handler接口  
     */
    public class LoggerInterceptor implements InvocationHandler {
        private Object target;//目标对象的引用,这里设计成Object类型,更具通用性  
        public LoggerInterceptor(Object target){  
            this.target = target;  
        }
        
        public Object invoke(Object proxy, Method method, Object[] arg)  throws Throwable {  
            System.out.println("Entered "+target.getClass().getName()+"-"+method.getName()+",with arguments{"+arg[0]+"}");  
            Object result = method.invoke(target, arg);//调用目标对象的方法  
            System.out.println("Before return:"+result);  
            return result;  
        }  
    }  
    复制代码

    外部调用

    public class Main {  
        public static void main(String[] args) {  
            AppService target = new AppServiceImpl();//生成目标对象  
            //接下来创建代理对象  
            AppService proxy = (AppService) Proxy.newProxyInstance(  
                    target.getClass().getClassLoader(),  
                    target.getClass().getInterfaces(), new LoggerInterceptor(target));  
            proxy.createApp("Kevin Test");  
        }  
    }  

    一、概述

    1. 什么是代理

    我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使用代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来:

    优点一:可以隐藏委托类的实现;

    优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

    2. 静态代理

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。 下面我们用Vendor类代表生产厂家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现,委托类和代理类都实现了Sell接口,Sell接口的定义如下:

    /**
     * 委托类和代理类都实现了Sell接口
     */
    public interface Sell { 
        void sell(); 
        void ad(); 
    } 
    复制代码

    Vendor类的定义如下:

    /**
     * 生产厂家
     */
    public class Vendor implements Sell { 
        public void sell() { 
            System.out.println("In sell method"); 
        } 
        
        public void ad() { 
            System,out.println("ad method");
        }
    } 
    复制代码

    代理类BusinessAgent的定义如下:

    /**
     * 代理类
     */
    public class BusinessAgent implements Sell {
        private Sell vendor;
        
        public BusinessAgent(Sell vendor){
            this.vendor = vendor;
        }
    
        public void sell() { 
            vendor.sell();
        } 
        
        public void ad() {
            vendor.ad();
        }
    } 
    复制代码

    从BusinessAgent类的定义我们可以了解到,静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。

    下面我们考虑一下这个需求:给Vendor类增加一个过滤功能,只卖货给大学生。通过静态代理,我们无需修改Vendor类的代码就可以实现,只需在BusinessAgent类中的sell方法中添加一个判断即可如下所示:

    /**
     * 代理类
     */
    public class BusinessAgent(){ implements Sell {
        private Sell vendor;
        
        public BusinessAgent(Sell vendor){
            this.vendor = vendor;
        }
    
        public void sell() {
            if (isCollegeStudent()) {
                vendor.sell();
            }
        } 
        
        public void ad() {
            vendor.ad();
        }
    } 
    复制代码

    这对应着我们上面提到的使用代理的第二个优点:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。静态代理的局限在于运行前必须编写好代理类,下面我们重点来介绍下运行时生成代理类的动态代理方式。

    二、动态代理

    1. 什么是动态代理

    代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。 这么说比较抽象,下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。

    现在,假设我们要实现这样一个需求:在执行委托类中的方法之前输出“before”,在执行完毕后输出“after”。我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类来进行介绍。首先我们来使用静态代理来实现这一需求,相关代码如下:

    public class BusinessAgent implements Sell {
        private Vendor mVendor; 
     
        public BusinessAgent(Vendor vendor) {
            this.mVendor = vendor; 
        } 
     
        public void sell() {
            System.out.println("before"); 
            mVendor.sell(); 
            System.out.println("after"); 
        } 
     
        public void ad() {
            System.out.println("before"); 
            mVendor.ad(); 
            System.out.println("after"); 
        }
    } 
    复制代码

    从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。下面我们来具体介绍下如何使用动态代理方式实现我们的需求。

    2. 使用动态代理

    2.1 InvocationHandler接口

    在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:

    /**
     * 调用处理程序
     */
    public interface InvocationHandler { 
        Object invoke(Object proxy, Method method, Object[] args); 
    } 
    复制代码

    从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。下面我们来一步一步具体实现它。

    2.2 委托类的定义

    动态代理方式下,要求委托类必须实现某个接口,这里我们实现的是Sell接口。委托类Vendor类的定义如下:

    public class Vendor implements Sell { 
        public void sell() { 
            System.out.println("In sell method"); 
        }
    
        public void ad() {
            System,out.println("ad method");
        }
    } 
    复制代码

    2.3中介类

    上面我们提到过,中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下:

    public class DynamicProxy implements InvocationHandler { 
        //obj为委托类对象; 
        private Object obj; 
     
        public DynamicProxy(Object obj) {
            this.obj = obj;
        } 
     
        @Override 
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
            System.out.println("before"); 
            Object result = method.invoke(obj, args); 
            System.out.println("after"); 
            return result; 
        }
    } 
    复制代码

    从以上代码中我们可以看到,中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法,看到这里是不是觉得似曾相识?

    通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗?

    实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;

    代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。

    也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。

    2.4动态生成代理类

    动态生成代理类的相关代码如下:

    public class Main { 
        public static void main(String[] args) {
            //创建中介类实例 
            DynamicProxy inter = new DynamicProxy(new Vendor()); 
            //加上这句将会产生一个$Proxy0.class文件,这个文件即为动态生成的代理类文件
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 
    
            //获取代理类实例sell 
            Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter)); 
     
            //通过代理类对象调用代理类方法,实际上会转到invoke方法调用 
            sell.sell(); 
            sell.ad(); 
        }
    } 
    复制代码

    在以上代码中,我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。这个方法的声明如下:

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

    方法的三个参数含义分别如下:

    loader:定义了代理类的ClassLoder; interfaces:代理类实现的接口列表 h:调用处理器,也就是我们上面定义的实现了InvocationHandler接口的类实例

    我们运行一下,看看我们的动态代理是否能正常工作。我这里运行后的输出为

     

    image

     

     

    说明我们的动态代理确实奏效了。

    上面我们已经简单提到过动态代理的原理,这里再简单的总结下:首先通过newProxyInstance方法获取代理类实例,而后我们便可以通过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法,在invoke方法中我们调用委托类的相应方法,并且可以添加自己的处理逻辑。

    三、代理模式

    这个应该是设计模式中最简单的一个了,类图

    image

     

     

    代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调用实际对象的操作

    Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理,这样说的比较笼统,举个简单的例子

    比如我们在应用中有这样一个需求,在对某个类的一个方法的调用前和调用后都要做一下日志操作,

    一个普通的接口

    public interface AppService {  
        public boolean createApp(String name);  
    }  
    复制代码

    该接口的默认实现类

    public class AppServiceImpl implements AppService {  
        public boolean createApp(String name) {  
            System.out.println("App["+name+"] has been created.");  
            return true;  
        }  
    }
    复制代码

    日志处理器(实质充当了中介类)

    /**
     * 注意需实现Handler接口  
     */
    public class LoggerInterceptor implements InvocationHandler {
        private Object target;//目标对象的引用,这里设计成Object类型,更具通用性  
        public LoggerInterceptor(Object target){  
            this.target = target;  
        }
        
        public Object invoke(Object proxy, Method method, Object[] arg)  throws Throwable {  
            System.out.println("Entered "+target.getClass().getName()+"-"+method.getName()+",with arguments{"+arg[0]+"}");  
            Object result = method.invoke(target, arg);//调用目标对象的方法  
            System.out.println("Before return:"+result);  
            return result;  
        }  
    }  
    复制代码

    外部调用

    public class Main {  
        public static void main(String[] args) {  
            AppService target = new AppServiceImpl();//生成目标对象  
            //接下来创建代理对象  
            AppService proxy = (AppService) Proxy.newProxyInstance(  
                    target.getClass().getClassLoader(),  
                    target.getClass().getInterfaces(), new LoggerInterceptor(target));  
            proxy.createApp("Kevin Test");  
        }  
    }  
    展开全文
  • java 动态代理

    2017-08-29 22:47:38
    java 动态代理deno
  • java 动态代理 简单实例 新手看看
  • JAVA动态代理,采用Proxy与InvocationHandler实现。
  • java动态代理demo

    2016-03-15 14:57:11
    适用于初探java动态代理模式,精简易懂。
  • 实现java动态代理的两个实例,jdk动态代理和cglib
  • java动态代理

    2011-09-14 15:36:38
    描述java动态代理,说明了怎么实现java的动态代理
  • 对应的博客链接:http://blog.csdn.net/JQ_AK47/article/details/60469034#t12
  • Java动态代理

    千次阅读 2017-09-26 10:43:00
    代理模式: 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理...动态代理:代理类是在运行时生成的,也就是说Java编译完之后并没有实际的class文件,而

    代理模式:

    代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

    这里写图片描述

    代理的实现分为

    • 静态代理:代理类是在编译时就实现好的,也就是说Java编译完成后代理类是一个实际的class文件
    • 动态代理:代理类是在运行时生成的,也就是说Java编译完之后并没有实际的class文件,而是在运行时动态生成的类字节码,并加载到JVM中。

    相关的类和接口

    要了解Java动态代理的机制,首先需要了解以下相关的类或接口:

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

    Proxy的静态方法

    // 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
    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)
    • java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个invoke方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

    InvocationHandler 的核心方法

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

    每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象

    • java.lang.ClassLoader: 这是类装载器类,负责将类的字节码装载到Java虚拟机中并为其定义类对象,然后该类才能被使用。Proxy静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由JVM在运行时动态生成的而非预存在于任何一个.class文件中。

    动态代理

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface IHello { // 定义接口
        public void sayHello();
    }
    
    class HelloImpl implements IHello {
        @Override
        public void sayHello() {
            // TODO Auto-generated method stub
            System.out.println("hello itmyhome");
        }
    }
    
    class MyInvocationHandler implements InvocationHandler {
        private Object obj; // 真实主题类
    
        public Object bind(Object obj) {
            this.obj = obj;
    
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
            System.out.println("***before***");
    
            Object temp = method.invoke(obj, args);
            System.out.println("***after***");
    
            return temp;
        }
    }
    
    public class Test {
        public static void main(String[] args) throws Exception {
            IHello h = (IHello) new MyInvocationHandler().bind(new HelloImpl());
            h.sayHello();
        }
    }

    Java动态代理的内部实现

    现在我们就会有一个问题:Java是怎么保证代理对象调用的任何方法都会调用InvocationHandler的invoke()方法的?
    这就涉及到动态代理的内部实现,假设有一个接口Subject,且里面有int request(int i)方法,则生成的代理类大致如下:

    public final class $Proxy1 extends Proxy implements Subject{
        private InvocationHandler h;
        private $Proxy1(){}
        public $Proxy1(InvocationHandler h){
            this.h = h;
        }
        public int request(int i){
            Method method = Subject.class.getMethod("request", new  []{int.class});    //创建method对象
            return (Integer)h.invoke(this, method, new Object[]{new Integer(i)}); //调用了invoke方法
        }
    }

    通过上面的方法就成功调用了 invoke() 方法。

    展开全文
  • 前言 如果你学习过spring,那么你一定接触和使用过Aop。...java原生的动态代理所代理的对象必须要实现一个顶级接口,而cglib的动态代理则不需要这样的接口。在很长一段时间里很迷惑为什么java的动态代...

    前言

    如果你学习过spring,那么你一定接触和使用过Aop。大家都知道Spring的Aop是采用动态代理方式实现的。而在Spring的Aop中使用的动态代理通常有两种:

    1. java原生的动态代理
    2. cglib的动态代理

    我们都学习过这两种代理方式的区别。java原生的动态代理所代理的对象必须要实现一个顶级接口,而cglib的动态代理则不需要这样的接口。在很长一段时间里很迷惑为什么java的动态代理一定要实现一个接口?

    所以带着疑问,我看了一下java动态代理的源码,这才找到问题所在。

    java代理大揭秘

    java代理实现

    首先我们来看下如何实现一个java的动态代理

    //定义一个接口,描述所有具有歌唱技能的人
    public interface IsSing {
    	public void sing();
    }
    
    //定义一个歌手类,实现IsSing是必须的,为什么需要实现这个接口,也是我们这次要解释的重点
    public class Singer implements IsSing {
    	public void sing(){
    		System.out.println("唱了一首歌");
    	}
    }
    
    //定义一个处理类
    //动态代理之所以能够增强原方法,就是因为这个类,在创建代理对象的时候需要将此类作为参数传入
    public class SingerAgentHandler implements InvocationHandler {
    
    	private IsSing singer;
    
    	public SingerAgentHandler(IsSing isSing) {
    		this.singer=isSing;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		System.out.println("和粉丝互动");
    		//执行原来的方法
    		Object object=method.invoke(singer,args);
    		System.out.println("鞠躬表示感谢");
    		return object;
    	}
    }
    
    //进行测试
    public class JavaAgentMain {
    	public static void main(String[] args) {
    		Singer singer=new Singer();
    		//创建一个代理对象
    		IsSing isSing= (IsSing) Proxy.newProxyInstance(Singer.class.getClassLoader()
    		,new Class[]{IsSing.class},new SingerAgentHandler(singer));
    		isSing.sing();
    	}
    }
    

    以上便是java动态代理的实现,可以看到,首先我们定义了一个IsSing的接口,之所以定义这个接口,是因为此接口是用以对拥有唱歌技能的一类人的抽象。该接口可以用来描述歌唱家,歌星,声乐老师等……,因为他们都有歌唱的技能(sing())。

    但是每个人在唱歌前后的状态和动作可能是不一样的,例如一个歌星在开演唱会,他可能在唱歌之前需要先和粉丝互动,而唱完歌之后可能需要对粉丝表示一些感谢之类的。这个时候sing()这个方法可能就不能完全的描述一个歌星的行为了。于是我们需要对sing()方法进行扩展,这也是代理存在的意义。

    所谓代理,既在保留原有公用功能的基础上,对特定的需要进行更进一步描述的行为进行增强。

    源码说明
    //创建一个代理对象
    IsSing isSing= (IsSing) Proxy.newProxyInstance(Singer.class.getClassLoader()
    ,new Class[]{IsSing.class},new SingerAgentHandler(singer));
    

    可以看到,在创建一个代理对象的时候,我们传入了三个参数

    • ClassLoader:类加载器,类加载器一般都是用来加载资源的
    • 顶级接口(IsSing):动态代理是动态的生成一个动态对象,从以上返回值就可以看出,他生成的对象必定是一个可以强转成IsSing的代理对象,即一个实现了IsSIng的对象
    • 增强Handler:用以对原方法进行扩展

    到这里,我们首先可以明确一点,java动态代理生成的对象会实现所定义的接口。
    但我们知道要让两个类之间产生关系,除了implement外还可以使用extends。但为什么java动态代理中不采用extends呢?

    我们比较一些两种方式的不同,大概就明白了采用“实现接口的方式”的必然性,因为大家都知道java的机制是不能进行多继承的,但可以进行多实现。

    回到我们的主题:为什么java动态代理必须要实现一个接口?

    我们现在可以给出一个猜测:因为java单继承的限制造成了java动态代理需要实现一个接口。

    接下来我们来看源码:

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    
             //获取代理类
            Class<?> cl = getProxyClass0(loader, intfs);
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    			//获取带有InvocationHandler.class的构造方法
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                //返回代理对象
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }
    

    上面的源码中核心是Class<?> cl = getProxyClass0(loader, intfs);该方法获取到一个代理类。我们进入该方法

    private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
            
            //从缓存中获取,找到proxyClassCache 定义的地方可以看到
            return proxyClassCache.get(loader, interfaces);
        }
    
    //其中包含一个ProxyClassFactory,该类负责动态生成一个代理对象
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
          proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
    //动态生成代理对象的工厂
    private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // prefix for all proxy class names
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // next number to use for generation of unique proxy class names
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    /*
                     * Verify that the class loader resolves the name of this
                     * interface to the same Class object.
                     */
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                    /*
                     * Verify that the Class object actually represents an
                     * interface.
                     */
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                    /*
                     * Verify that this interface is not a duplicate.
                     */
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * Record the package of a non-public proxy interface so that the
                 * proxy class will be defined in the same package.  Verify that
                 * all non-public proxy interfaces are in the same package.
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;
                        String name = intf.getName();
                        int n = name.lastIndexOf('.');
                        String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                        if (proxyPkg == null) {
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {
                            throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    //默认生成的代理对象的包围com.sun.proxy
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                //默认代理对象名称为$Proxy+数字
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
               //获取一个代理类的字节码
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    /*
                     * A ClassFormatError here means that (barring bugs in the
                     * proxy class generation code) there was some other
                     * invalid aspect of the arguments supplied to the proxy
                     * class creation (such as virtual machine limitations
                     * exceeded).
                     */
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }
    

    从上面源码我们知道,动态生成的代理类默认放在com.sun.proxy中,并且类名为$Proxy为前缀。

    对我们测试方法改造下

    public static void main(String[] args) {
    		Singer singer=new Singer();
    		 //设置系统属性,设置后产生的代理类会保存到com.sun.proxy中
    		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    		IsSing isSing= (IsSing) Proxy.newProxyInstance(Singer.class.getClassLoader(),new Class[]{IsSing.class},new SingerAgentHandler(singer));
    		isSing.sing();
    	}
    

    反编译类文件可以看到

    在这里插入图片描述
    可以看到生成的代理类中继承了Poxy类,所以由于java的单继承特点,java生成代理类就必须只有implete接口这一条路可走了。

    总结

    总的来说,java提供的代理实现,之所以要求我们必须提供一个接口,是因为它在生成代理类的时候已经继承了Proxy类,只能通过实现的方式来建立与我们需要代理的类的联系。

    展开全文
  • java动态代理实现

    千次阅读 2019-01-15 14:42:46
    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。  一、代理模式  代理模式是常用的java设计模式,他的特征是...

    转载:https://www.cnblogs.com/xifengxiaoma/p/9371771.html

    目录

     一、代理模式

    二、静态代理

    三、动态代理


    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。

     一、代理模式

       代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。在后面我会

    解释这种间接性带来的好处。代理模式结构图(图片来自《大话设计模式》):

                                                              

    二、静态代理

        1、静态代理

    静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

        2、静态代理简单实现

      根据上面代理模式的类图,来写一个简单的静态代理的例子。我这儿举一个比较粗糙的例子,假如一个班的同学要向老师交班费,但是都是通过班长把自己的钱转交给老师。这里,班长就是代理学生上交班费,

    班长就是学生的代理。

        首先,我们创建一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有上交班费的行为。这样,学生上交班费就可以让班长来代理执行。

     

    /**
     * 创建Person接口
     * @author Gonjan
     */
    public interface Person {
        //上交班费
        void giveMoney();
    }

    Student类实现Person接口。Student可以具体实施上交班费的动作。

    public class Student implements Person {
        private String name;
        public Student(String name) {
            this.name = name;
        }
        
        @Override
        public void giveMoney() {
           System.out.println(name + "上交班费50元");
        }
    }

    StudentsProxy类,这个类也实现了Person接口,但是还另外持有一个学生类对象,由于实现了Peson接口,同时持有一个学生对象,那么他可以代理学生类对象执行上交班费(执行giveMoney()方法)行为。

    /**
     * 学生代理类,也实现了Person接口,保存一个学生实体,这样既可以代理学生产生行为
     * @author Gonjan
     *
     */
    public class StudentsProxy implements Person{
        //被代理的学生
        Student stu;
        
        public StudentsProxy(Person stu) {
            // 只代理学生对象
            if(stu.getClass() == Student.class) {
                this.stu = (Student)stu;
            }
        }
        
        //代理上交班费,调用被代理学生的上交班费行为
        public void giveMoney() {
            stu.giveMoney();
        }
    }

    下面测试一下,看如何使用代理模式:

    public class StaticProxyTest {
        public static void main(String[] args) {
            //被代理的学生张三,他的班费上交有代理对象monitor(班长)完成
            Person zhangsan = new Student("张三");
            
            //生成代理对象,并将张三传给代理对象
            Person monitor = new StudentsProxy(zhangsan);
            
            //班长代理上交班费
            monitor.giveMoney();
        }
    }

    运行结果:

    这里并没有直接通过张三(被代理对象)来执行上交班费的行为,而是通过班长(代理对象)来代理执行了。这就是代理模式。

    代理模式最主要的就是有一个公共接口(Person),一个具体的类(Student),一个代理类(StudentsProxy),代理类持有具体类的实例,代为执行具体类实例方法。上面说到,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。就这个例子来说,加入班长在帮张三上交班费之前想要先反映一下张三最近学习有很大进步,通过代理模式很轻松就能办到:

    public class StudentsProxy implements Person{
        //被代理的学生
        Student stu;
        
        public StudentsProxy(Person stu) {
            // 只代理学生对象
            if(stu.getClass() == Student.class) {
                this.stu = (Student)stu;
            }
        }
        
        //代理上交班费,调用被代理学生的上交班费行为
        public void giveMoney() {
            System.out.println("张三最近学习有进步!");
            stu.giveMoney();
        }
    }

    运行结果:

    可以看到,只需要在代理类中帮张三上交班费之前,执行其他操作就可以了。这种操作,也是使用代理模式的一个很大的优点。最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。

    三、动态代理

         1.动态代理

        代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(studentProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。 比如说,想要在每个代理的方法前都加上一个处理方法:

     public void giveMoney() {
            //调用被代理方法前加入处理方法
            beforeMethod();
            stu.giveMoney();
        }

     

    这里只有一个giveMoney方法,就写一次beforeMethod方法,但是如果出了giveMonney还有很多其他的方法,那就需要写很多次beforeMethod方法,麻烦。那看看下面动态代理如何实现。

         2、动态代理简单实现

    在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

    创建一个动态代理对象步骤,具体代码见后面:

    • 创建一个InvocationHandler对象
    //创建一个与代理对象相关联的InvocationHandler
     InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu);

     

     

    • 使用Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass 
      Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[] {Person.class});

     

    • 获得stuProxyClass 中一个带InvocationHandler参数的构造器constructor
    Constructor<?> constructor = PersonProxy.getConstructor(InvocationHandler.class);

     

    • 通过构造器constructor来创建一个动态实例stuProxy
    Person stuProxy = (Person) cons.newInstance(stuHandler);

     

    就此,一个动态代理对象就创建完毕,当然,上面四个步骤可以通过Proxy类的newProxyInstances方法来简化:

     //创建一个与代理对象相关联的InvocationHandler
      InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu);
    //创建一个代理对象stuProxy,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
      Person stuProxy= (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

     

    到这里肯定都会很疑惑,这动态代理到底是如何执行的,是如何通过代理对象来执行被代理对象的方法的,先不急,我们先看看一个简单的完整的动态代理的例子。还是上面静态代理的例子,班长需要帮学生代交班费。
    首先是定义一个Person接口:

     

    /**
     * 创建Person接口
     * @author Gonjan
     */
    public interface Person {
        //上交班费
        void giveMoney();
    }

    创建需要被代理的实际类:

    public class Student implements Person {
        private String name;
        public Student(String name) {
            this.name = name;
        }
        
        @Override
        public void giveMoney() {
            try {
              //假设数钱花了一秒时间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
           System.out.println(name + "上交班费50元");
        }
    }        

    再定义一个检测方法执行时间的工具类,在任何方法执行前先调用start方法,执行后调用finsh方法,就可以计算出该方法的运行时间,这也是一个最简单的方法执行时间检测工具。

     

    public class MonitorUtil {
        
        private static ThreadLocal<Long> tl = new ThreadLocal<>();
        
        public static void start() {
            tl.set(System.currentTimeMillis());
        }
        
        //结束时打印耗时
        public static void finish(String methodName) {
            long finishTime = System.currentTimeMillis();
            System.out.println(methodName + "方法耗时" + (finishTime - tl.get()) + "ms");
        }
    }

     

    创建StuInvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。

    再再invoke方法中执行被代理对象target的相应方法。当然,在代理过程中,我们在真正执行被代理对象的方法前加入自己其他处理。这也是Spring中的AOP实现的主要原理,这里还涉及到一个很重要的关于java反射方面的基础知识。

     

    public class StuInvocationHandler<T> implements InvocationHandler {
       //invocationHandler持有的被代理对象
        T target;
        
        public StuInvocationHandler(T target) {
           this.target = target;
        }
        
        /**
         * proxy:代表动态代理对象
         * method:代表正在执行的方法
         * args:代表调用目标方法时传入的实参
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("代理执行" +method.getName() + "方法");
         */   
            //代理过程中插入监测方法,计算该方法耗时
            MonitorUtil.start();
            Object result = method.invoke(target, args);
            MonitorUtil.finish(method.getName());
            return result;
        }
    }

    复制代码

    复制代码

    做完上面的工作后,我们就可以具体来创建动态代理对象了,上面简单介绍了如何创建动态代理对象,我们使用简化的方式创建动态代理对象:

     

    public class ProxyTest {
        public static void main(String[] args) {
            
            //创建一个实例对象,这个对象是被代理的对象
            Person zhangsan = new Student("张三");
            
            //创建一个与代理对象相关联的InvocationHandler
            InvocationHandler stuHandler = new StuInvocationHandler<Person>(zhangsan);
            
            //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
            Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
    
           //代理执行上交班费的方法
            stuProxy.giveMoney();
        }

     

    我们执行这个ProxyTest类,先想一下,我们创建了一个需要被代理的学生张三,将zhangsan对象传给了stuHandler中,我们在创建代理对象stuProxy时,将stuHandler作为参数了的,上面也有说到所有执行代理对象的方法都会被替换成执行invoke方法,也就是说,最后执行的是StuInvocationHandler中的invoke方法。所以在看到下面的运行结果也就理所当然了。

    运行结果:

    上面说到,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。例如,这里的方法计时,所有的被代理对象执行的方法都会被计时,然而我只做了很少的代码量。

    动态代理的过程,代理对象和被代理对象的关系不像静态代理那样一目了然,清晰明了。因为动态代理的过程中,我们并没有实际看到代理类,也没有很清晰地的看到代理类的具体样子,而且动态代理中被代理对象和代理对象是通过InvocationHandler来完成的代理过程的,其中具体是怎样操作的,为什么代理对象执行的方法都会通过InvocationHandler中的invoke方法来执行。带着这些问题,我们就需要对java动态代理的源码进行简要的分析,弄清楚其中缘由。

    展开全文
  • NULL 博文链接:https://jadeluo.iteye.com/blog/1940019
  • Java实现动态代理

    2017-12-01 14:22:50
    这几个文件是我当时自己总结的,这几天突然翻出来了,上传上来给需要的同学们看看,说不定有人需要呢
  • Java 动态代理 借用电子商务模式来说明
  • java动态代理详解及实际应用

    千次阅读 热门讨论 2021-02-24 21:58:45
    重点教你如何应用先回顾一下代理模式使用场景1:动态代理+反射 实现hook技术AOP(面向切面编程) 先回顾一下代理模式 代理模式分动态代理和静态代理,写起来也比较简单,先上代码: public interface Goal { void ...
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解动态代理原理,对学习AOP框架至关重要。 JDK动态代理不需要任何外部依赖,但是只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有...
  • java动态代理详解

    万次阅读 多人点赞 2018-08-21 15:32:51
    目前java动态代理的实现分为两种 1.基于JDK的动态代理 2.基于CGILB的动态代理 在业务中使用动态代理,一般是为了给需要实现的方法添加预处理或者添加后续操作,但是不干预实现类的正常业务,把一些基本业务和主要...
  • java动态代理实现接口调用

    千次阅读 2019-10-14 11:17:33
    动态代理是基于接口实现的代理,mybatis就是用这个技术实现的 首先,创建一个最基本接口和实现类: interface UserManager { void addUser(); } class UserManagerImpl implements UserManager{ @Override ...
  • Java 动态代理

    万次阅读 多人点赞 2018-07-24 23:42:58
    一、什么是代理代理是一种常用的设计模式,其目的就是为真实对象提供一个代理对象以控制对真实对象的访问。代理类负责为委托类(被代理类、真实类)预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后...
  • 四、动态代理的JDK实现原理 4.1核心类/接口 4.2 代理类$Proxy0解析 4.3 动态代理的经典使用五、手写代码模拟JDK动态代理六、参考资料项目源码已经上传,欢迎点击下载~先将自己总结的Java动态代理UML图放在前面,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 268,438
精华内容 107,375
关键字:

java动态代理

java 订阅