精华内容
下载资源
问答
  • Java两种动态代理JDK动态代理和CGLIB动态代理

    万次阅读 多人点赞 2018-08-07 15:33:35
    目录 代理模式 JDK动态代理 ...但是B是“真正”实现类,A则比较“虚”,他借用了B的方法去实现接口的方法。A虽然是“伪军”,但它可以增强B,在调用B的方法前后都做些其他的事情。Spring AOP...

    目录

    代理模式

    JDK动态代理

    cglib动态代理

    测试


    代理模式

    代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是“真正”实现类,A则比较“虚”,他借用了B的方法去实现接口的方法。A虽然是“伪军”,但它可以增强B,在调用B的方法前后都做些其他的事情。Spring AOP就是使用了动态代理完成了代码的动态“织入”。

    使用代理好处还不止这些,一个工程如果依赖另一个工程给的接口,但是另一个工程的接口不稳定,经常变更协议,就可以使用一个代理,接口变更时,只需要修改代理,不需要一一修改业务代码。从这个意义上说,所有调外界的接口,我们都可以这么做,不让外界的代码对我们的代码有侵入,这叫防御式编程。代理其他的应用可能还有很多。

    上述例子中,类A写死持有B,就是B的静态代理。如果A代理的对象是不确定的,就是动态代理。动态代理目前有两种常见的实现,jdk动态代理和cglib动态代理。

    JDK动态代理

    jdk动态代理是jre提供给我们的类库,可以直接使用,不依赖第三方。先看下jdk动态代理的使用代码,再理解原理。

    首先有个“明星”接口类,有唱、跳两个功能:

    package proxy;
    
    public interface Star
    {
        String sing(String name);
        
        String dance(String name);
    }
    

    再有个明星实现类“刘德华”:

    package proxy;
    
    public class LiuDeHua implements Star
    {   
        @Override
        public String sing(String name)
        {
             System.out.println("给我一杯忘情水");
    
            return "唱完" ;
        }
        
        @Override
        public String dance(String name)
        {
            System.out.println("开心的马骝");
    
            return "跳完" ;
        }
    }
    

    明星演出前需要有人收钱,由于要准备演出,自己不做这个工作,一般交给一个经纪人。便于理解,它的名字以Proxy结尾,但他不是代理类,原因是它没有实现我们的明星接口,无法对外服务,它仅仅是一个wrapper。

    package proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class StarProxy implements InvocationHandler
    {
        // 目标类,也就是被代理对象
        private Object target;
        
        public void setTarget(Object target)
        {
            this.target = target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            // 这里可以做增强
            System.out.println("收钱");
            
            Object result = method.invoke(target, args);
            
            return result;
        }
        
        // 生成代理类
        public Object CreatProxyedObj()
        {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }  
       
    }
    

    上述例子中,方法CreatProxyedObj返回的对象才是我们的代理类,它需要三个参数,前两个参数的意思是在同一个classloader下通过接口创建出一个对象,该对象需要一个属性,也就是第三个参数,它是一个InvocationHandler。需要注意的是这个CreatProxyedObj方法不一定非得在我们的StarProxy类中,往往放在一个工厂类中。上述代理的代码使用过程一般如下:

    1、new一个目标对象

    2、new一个InvocationHandler,将目标对象set进去

    3、通过CreatProxyedObj创建代理对象,强转为目标对象的接口类型即可使用,实际上生成的代理对象实现了目标接口。

            Star ldh = new LiuDeHua();
    
            StarProxy proxy = new StarProxy();
    
            proxy.setTarget(ldh); 
      
            Object obj = proxy.CreatProxyedObj();
            
            Star star = (Star)obj;

    Proxy(jdk类库提供)根据B的接口生成一个实现类,我们成为C,它就是动态代理类(该类型是 $Proxy+数字 的“新的类型”)。生成过程是:由于拿到了接口,便可以获知接口的所有信息(主要是方法的定义),也就能声明一个新的类型去实现该接口的所有方法,这些方法显然都是“虚”的,它调用另一个对象的方法。当然这个被调用的对象不能是对象B,如果是对象B,我们就没法增强了,等于饶了一圈又回来了。

    所以它调用的是B的包装类,这个包装类需要我们来实现,但是jdk给出了约束,它必须实现InvocationHandler,上述例子中就是StarProxy, 这个接口里面有个方法,它是所有Target的所有方法的调用入口(invoke),调用之前我们可以加自己的代码增强。

    看下我们的实现,我们在InvocationHandler里调用了对象B(target)的方法,调用之前增强了B的方法。

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            // 这里增强
            System.out.println("收钱");
            
            Object result = method.invoke(target, args);
            
            return result;
        }

    所以可以这么认为C代理了InvocationHandler,InvocationHandler代理了我们的类B,两级代理。

    整个JDK动态代理的秘密也就这些,简单一句话,动态代理就是要生成一个包装类对象,由于代理的对象是动态的,所以叫动态代理。由于我们需要增强,这个增强是需要留给开发人员开发代码的,因此代理类不能直接包含被代理对象,而是一个InvocationHandler,该InvocationHandler包含被代理对象,并负责分发请求给被代理对象,分发前后均可以做增强。从原理可以看出,JDK动态代理是“对象”的代理。

    下面看下动态代理类到底如何调用的InvocationHandler的,为什么InvocationHandler的一个invoke方法能为分发target的所有方法。C中的部分代码示例如下,通过反编译生成后的代码查看,摘自链接地址。Proxy创造的C是自己(Proxy)的子类,且实现了B的接口,一般都是这么修饰的:

    public final class XXX extends Proxy implements XXX
    

    一个方法代码如下:

    
      public final String SayHello(String paramString)
      {
        try
        {
          return (String)this.h.invoke(this, m4, new Object[] { paramString });
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
    

    可以看到,C中的方法全部通过调用h实现,其中h就是InvocationHandler,是我们在生成C时传递的第三个参数。这里还有个关键就是SayHello方法(业务方法)跟调用invoke方法时传递的参数m4一定要是一一对应的,但是这些对我们来说都是透明的,由Proxy在newProxyInstance时保证的。留心看到C在invoke时把自己this传递了过去,InvocationHandler的invoke的第一个方法也就是我们的动态代理实例类,业务上有需要就可以使用它。(所以千万不要在invoke方法里把请求分发给第一个参数,否则很明显就死循环了)

    C类中有B中所有方法的成员变量

      private static Method m1;
      private static Method m3;
      private static Method m4;
      private static Method m2;
      private static Method m0;
    

    这些变量在static静态代码块初始化,这些变量是在调用invocationhander时必要的入参,也让我们依稀看到Proxy在生成C时留下的痕迹。

    static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
          m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    

    从以上分析来看,要想彻底理解一个东西,再多的理论不如看源码,底层的原理非常重要。

    jdk动态代理类图如下

    cglib动态代理

    我们了解到,“代理”的目的是构造一个和被代理的对象有同样行为的对象,一个对象的行为是在类中定义的,对象只是类的实例。所以构造代理,不一定非得通过持有、包装对象这一种方式。

    通过“继承”可以继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。根据里氏代换原则(LSP),父类需要出现的地方,子类可以出现,所以cglib实现的代理也是可以被正常使用的。

    先看下代码

    package proxy;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class CglibProxy implements MethodInterceptor
    {
        // 根据一个类型产生代理类,此方法不要求一定放在MethodInterceptor中
        public Object CreatProxyedObj(Class<?> clazz)
        {
            Enhancer enhancer = new Enhancer();
            
            enhancer.setSuperclass(clazz);
            
            enhancer.setCallback(this);
            
            return enhancer.create();
        }
        
        @Override
        public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
        {
            // 这里增强
            System.out.println("收钱");
            
            return arg3.invokeSuper(arg0, arg2);
        } 
    }
    

    从代码可以看出,它和jdk动态代理有所不同,对外表现上看CreatProxyedObj,它只需要一个类型clazz就可以产生一个代理对象, 所以说是“类的代理”,且创造的对象通过打印类型发现也是一个新的类型。不同于jdk动态代理,jdk动态代理要求对象必须实现接口(三个参数的第二个参数),cglib对此没有要求。

    cglib的原理是这样,它生成一个继承B的类型C(代理类),这个代理类持有一个MethodInterceptor,我们setCallback时传入的。 C重写所有B中的方法(方法名一致),然后在C中,构建名叫“CGLIB”+“$父类方法名$”的方法(下面叫cglib方法,所有非private的方法都会被构建),方法体里只有一句话super.方法名(),可以简单的认为保持了对父类方法的一个引用,方便调用。

    这样的话,C中就有了重写方法、cglib方法、父类方法(不可见),还有一个统一的拦截方法(增强方法intercept)。其中重写方法和cglib方法肯定是有映射关系的。

    C的重写方法是外界调用的入口(LSP原则),它调用MethodInterceptor的intercept方法,调用时会传递四个参数,第一个参数传递的是this,代表代理类本身,第二个参数标示拦截的方法,第三个参数是入参,第四个参数是cglib方法,intercept方法完成增强后,我们调用cglib方法间接调用父类方法完成整个方法链的调用。

    这里有个疑问就是intercept的四个参数,为什么我们使用的是arg3而不是arg1?

        @Override
        public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
        {
            System.out.println("收钱");
            
            return arg3.invokeSuper(arg0, arg2);
        }

     因为如果我们通过反射 arg1.invoke(arg0, ...)这种方式是无法调用到父类的方法的,子类有方法重写,隐藏了父类的方法,父类的方法已经不可见,如果硬调arg1.invoke(arg0, ...)很明显会死循环。

    所以调用的是cglib开头的方法,但是,我们使用arg3也不是简单的invoke,而是用的invokeSuper方法,这是因为cglib采用了fastclass机制,不仅巧妙的避开了调不到父类方法的问题,还加速了方法的调用。

    fastclass基本原理是,给每个方法编号,通过编号找到方法执行避免了通过反射调用。

    对比JDK动态代理,cglib依然需要一个第三者分发请求,只不过jdk动态代理分发给了目标对象,cglib最终分发给了自己,通过给method编号完成调用。cglib是继承的极致发挥,本身还是很简单的,只是fastclass需要另行理解。

    参考

    https://blog.csdn.net/jiankunking/article/details/52143504

    http://www.php.cn/java-article-407212.html

    https://www.cnblogs.com/chinajava/p/5880887.html

    https://rejoy.iteye.com/blog/1627405

    测试

       public static void main(String[] args)
        {
            int times = 1000000;
            
            Star ldh = new LiuDeHua();
            StarProxy proxy = new StarProxy();
            proxy.setTarget(ldh);
            
            long time1 = System.currentTimeMillis();
            Star star = (Star)proxy.CreatProxyedObj();
            long time2 = System.currentTimeMillis();
            System.out.println("jdk创建时间:" + (time2 - time1));
            
            CglibProxy proxy2 = new CglibProxy();
            long time5 = System.currentTimeMillis();
            Star star2 = (Star)proxy2.CreatProxyedObj(LiuDeHua.class);
            long time6 = System.currentTimeMillis();
            System.out.println("cglib创建时间:" + (time6 - time5));
            
            long time3 = System.currentTimeMillis();
            for (int i = 1; i <= times; i++)
            {
                star.sing("ss");
                
                star.dance("ss");
            }
            long time4 = System.currentTimeMillis();
            System.out.println("jdk执行时间" + (time4 - time3));
            
            long time7 = System.currentTimeMillis();
            for (int i = 1; i <= times; i++)
            {
                star2.sing("ss");
                
                star2.dance("ss");
            }
            
            long time8 = System.currentTimeMillis();
            
            System.out.println("cglib执行时间" + (time8 - time7));   
        }

    经测试,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。

    展开全文
  • java动态代理--代理接口无实现类

    千次阅读 2017-04-03 13:15:32
    使用通过接口定义,或解析接口注解等完成相关功能,如mybatis的SqlSession.getMapper的实现 接口定义 ... public interface IHello { ...代理实现 package cn.proxy; import java.lang.reflect.Invocatio

    使用通过接口定义,或解析接口注解等完成相关功能,如mybatis的SqlSession.getMapper的实现

    1. 接口定义
    package cn.proxy;  
    
    public interface IHello {  
        String say(String aa);  
    }  
    1. 代理实现
    package cn.proxy;  
    import java.lang.reflect.InvocationHandler;  
    import java.lang.reflect.Method;  
    import java.lang.reflect.Proxy;  
    /** 
      JDK动态代理代理类  
     */  
    @SuppressWarnings("unchecked")  
    public class FacadeProxy implements InvocationHandler {    
        @Override    
        public Object invoke(Object proxy, Method method, Object[] args)    
                throws Throwable {    
            System.out.println("接口方法调用开始");    
            //执行方法    
            System.out.println("method toGenericString:"+method.toGenericString());  
            System.out.println("method name:"+method.getName());  
            System.out.println("method args:"+(String)args[0]);  
            System.out.println("接口方法调用结束");    
            return "调用返回值";    
        }    
        public static <T> T newMapperProxy(Class<T> mapperInterface) {  
            ClassLoader classLoader = mapperInterface.getClassLoader();  
            Class<?>[] interfaces = new Class[]{mapperInterface};  
            FacadeProxy proxy = new FacadeProxy();  
            return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);  
          }  
    }  
    1. 运行
    package cn.proxy;  
    
    public class Test {  
        public static void main(String[] args) {  
            IHello hello = FacadeProxy.newMapperProxy(IHello.class);  
            System.out.println(hello.say("hello world"));  
        }  
    }  
    1. 运行结果
    接口方法调用开始  
    method toGenericString:public abstract java.lang.String cn.proxy.IHello.say(java.lang.String)  
    method name:say  
    method args:hello world  
    接口方法调用结束  
    调用返回值 

    转载于http://blog.csdn.net/zhu_tianwei/article/details/40076391

    展开全文
  • Java JDK 动态代理(AOP)使用及实现原理分析

    万次阅读 多人点赞 2019-05-08 21:28:06
    二、Java 动态代理类 三、JDK的动态代理怎么使用? 四、动态代理怎么实现的? 五、结论 一、什么是代理代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为...

    目录

    一、什么是代理?

    二、Java 动态代理类 

    三、JDK的动态代理怎么使用?

    四、动态代理怎么实现的?

    五、结论


    一、什么是代理?

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

    代理模式UML图:

    简单结构示意图:

    为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

    二、Java 动态代理类 

    Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

    (1)Interface InvocationHandler:该接口中仅定义了一个方法

    public object invoke(Object obj,Method method, Object[] args)

    在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

    (2)Proxy:该类即为动态代理类,其中主要包含以下内容:

    protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

    static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

    static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

    所谓DynamicProxy是这样一种class:它是在运行时生成的class在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作

    在使用动态代理类时,我们必须实现InvocationHandler接口

    通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject)也可以动态改变,从而实现了非常灵活的动态代理关系。

    动态代理步骤
    1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
    2.创建被代理的类以及接口
    3.通过Proxy的静态方法
    newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
    4.通过代理调用方法

    三、JDK的动态代理怎么使用?

    1、需要动态代理的接口:

    package jiankunking;
    
    /**
     * 需要动态代理的接口
     */
    public interface Subject
    {
        /**
         * 你好
         *
         * @param name
         * @return
         */
        public String SayHello(String name);
    
        /**
         * 再见
         *
         * @return
         */
        public String SayGoodBye();
    }

    2、需要代理的实际对象

    package jiankunking;
    
    /**
     * 实际对象
     */
    public class RealSubject implements Subject
    {
    
        /**
         * 你好
         *
         * @param name
         * @return
         */
        public String SayHello(String name)
        {
            return "hello " + name;
        }
    
        /**
         * 再见
         *
         * @return
         */
        public String SayGoodBye()
        {
            return " good bye ";
        }
    }

    3、调用处理器实现类(有木有感觉这里就是传说中的AOP啊)

    package jiankunking;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    
    /**
     * 调用处理器实现类
     * 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象
     */
    public class InvocationHandlerImpl implements InvocationHandler
    {
    
        /**
         * 这个就是我们要代理的真实对象
         */
        private Object subject;
    
        /**
         * 构造方法,给我们要代理的真实对象赋初值
         *
         * @param subject
         */
        public InvocationHandlerImpl(Object subject)
        {
            this.subject = subject;
        }
    
        /**
         * 该方法负责集中处理动态代理类上的所有方法调用。
         * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
         *
         * @param proxy  代理类实例
         * @param method 被调用的方法对象
         * @param args   调用参数
         * @return
         * @throws Throwable
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            //在代理真实对象前我们可以添加一些自己的操作
            System.out.println("在调用之前,我要干点啥呢?");
    
            System.out.println("Method:" + method);
    
            //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
            Object returnValue = method.invoke(subject, args);
    
            //在代理真实对象后我们也可以添加一些自己的操作
            System.out.println("在调用之后,我要干点啥呢?");
    
            return returnValue;
        }
    }

    4、测试

    package jiankunking;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理演示
     */
    public class DynamicProxyDemonstration
    {
        public static void main(String[] args)
        {
            //代理的真实对象
            Subject realSubject = new RealSubject();
            
            /**
             * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
             * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
             * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
             */
            InvocationHandler handler = new InvocationHandlerImpl(realSubject);
    
            ClassLoader loader = realSubject.getClass().getClassLoader();
            Class[] interfaces = realSubject.getClass().getInterfaces();
            /**
             * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
             */
            Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
    
            System.out.println("动态代理对象的类型:"+subject.getClass().getName());
    
            String hello = subject.SayHello("jiankunking");
            System.out.println(hello);
    //        String goodbye = subject.SayGoodBye();
    //        System.out.println(goodbye);
        }
    
    }

    5、输出结果如下:

    演示demo下载地址:http://download.csdn.net/detail/xunzaosiyecao/9597388

    四、动态代理怎么实现的?

    从使用代码中可以看出,关键点在:

    Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

    通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。

    也就是说,当代码执行到:

    subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?

    ==============横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论===================

    以下代码来自:JDK1.8.0_92

    既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么? 

    /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * {@code IllegalArgumentException} for the same reasons that
     * {@code Proxy.getProxyClass} does.
     *
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     * @throws  IllegalArgumentException if any of the restrictions on the
     *          parameters that may be passed to {@code getProxyClass}
     *          are violated
     * @throws  SecurityException if a security manager, <em>s</em>, is present
     *          and any of the following conditions is met:
     *          <ul>
     *          <li> the given {@code loader} is {@code null} and
     *               the caller's class loader is not {@code null} and the
     *               invocation of {@link SecurityManager#checkPermission
     *               s.checkPermission} with
     *               {@code RuntimePermission("getClassLoader")} permission
     *               denies access;</li>
     *          <li> for each proxy interface, {@code intf},
     *               the caller's class loader is not the same as or an
     *               ancestor of the class loader for {@code intf} and
     *               invocation of {@link SecurityManager#checkPackageAccess
     *               s.checkPackageAccess()} denies access to {@code intf};</li>
     *          <li> any of the given proxy interfaces is non-public and the
     *               caller class is not in the same {@linkplain Package runtime package}
     *               as the non-public interface and the invocation of
     *               {@link SecurityManager#checkPermission s.checkPermission} with
     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
     *               permission denies access.</li>
     *          </ul>
     * @throws  NullPointerException if the {@code interfaces} array
     *          argument or any of its elements are {@code null}, or
     *          if the invocation handler, {@code h}, is
     *          {@code null}
     */
    @CallerSensitive 
    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
    		//检查h 不为空,否则抛异常
            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);
                }
    			//获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h)) 
                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;
                        }
                    });
                }
    			//生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法
                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);
            }
        }

    我们再进去getProxyClass0方法看一下:

     /**
         * Generate a proxy class.  Must call the checkProxyAccess method
         * to perform permission checks before calling this.
         */
        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
            // If the proxy class defined by the given loader implementing
            // the given interfaces exists, this will simply return the cached copy;
            // otherwise, it will create the proxy class via the ProxyClassFactory
            return proxyClassCache.get(loader, interfaces);
        }

    真相还是没有来到,继续,看一下 proxyClassCache

    /**
         * a cache of proxy classes
         */
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    奥,原来用了一下缓存啊

    那么它对应的get方法啥样呢?

     /**
         * Look-up the value through the cache. This always evaluates the
         * {@code subKeyFactory} function and optionally evaluates
         * {@code valueFactory} function if there is no entry in the cache for given
         * pair of (key, subKey) or the entry has already been cleared.
         *
         * @param key       possibly null key
         * @param parameter parameter used together with key to create sub-key and
         *                  value (should not be null)
         * @return the cached value (never null)
         * @throws NullPointerException if {@code parameter} passed in or
         *                              {@code sub-key} calculated by
         *                              {@code subKeyFactory} or {@code value}
         *                              calculated by {@code valueFactory} is null.
         */
        public V get(K key, P parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
    
            Object cacheKey = CacheKey.valueOf(key, refQueue);
    
            // lazily install the 2nd level valuesMap for the particular cacheKey
            ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
            if (valuesMap == null) {
    			//putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入
                ConcurrentMap<Object, Supplier<V>> oldValuesMap
                    = map.putIfAbsent(cacheKey,
                                      valuesMap = new ConcurrentHashMap<>());
                if (oldValuesMap != null) {
                    valuesMap = oldValuesMap;
                }
            }
    
            // create subKey and retrieve the possible Supplier<V> stored by that
            // subKey from valuesMap
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            Supplier<V> supplier = valuesMap.get(subKey);
            Factory factory = null;
    
            while (true) {
                if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }
                // else no supplier in cache
                // or a supplier that returned null (could be a cleared CacheValue
                // or a Factory that wasn't successful in installing the CacheValue)
    
                // lazily construct a Factory
                if (factory == null) {
                    factory = new Factory(key, parameter, subKey, valuesMap);
                }
    
                if (supplier == null) {				
                    supplier = valuesMap.putIfAbsent(subKey, factory);
                    if (supplier == null) {
                        // successfully installed Factory
                        supplier = factory;
                    }
                    // else retry with winning supplier
                } else {
                    if (valuesMap.replace(subKey, supplier, factory)) {
                        // successfully replaced
                        // cleared CacheEntry / unsuccessful Factory
                        // with our Factory
                        supplier = factory;
                    } else {
                        // retry with current supplier
                        supplier = valuesMap.get(subKey);
                    }
                }
            }
        }

    我们可以看到它调用了 supplier.get(); 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。

    来瞅瞅,get里面又做了什么?

     public synchronized V get() { // serialize access
                // re-check
                Supplier<V> supplier = valuesMap.get(subKey);
                if (supplier != this) {
                    // something changed while we were waiting:
                    // might be that we were replaced by a CacheValue
                    // or were removed because of failure ->
                    // return null to signal WeakCache.get() to retry
                    // the loop
                    return null;
                }
                // else still us (supplier == this)
    
                // create new value
                V value = null;
                try {
                    value = Objects.requireNonNull(valueFactory.apply(key, parameter));
                } finally {
                    if (value == null) { // remove us on failure
                        valuesMap.remove(subKey, this);
                    }
                }
                // the only path to reach here is with non-null value
                assert value != null;
    
                // wrap value with CacheValue (WeakReference)
                CacheValue<V> cacheValue = new CacheValue<>(value);
    
                // try replacing us with CacheValue (this should always succeed)
                if (valuesMap.replace(subKey, this, cacheValue)) {
                    // put also in reverseMap
                    reverseMap.put(cacheValue, Boolean.TRUE);
                } else {
                    throw new AssertionError("Should not reach here");
                }
    
                // successfully replaced us with new CacheValue -> return the value
                // wrapped by it
                return value;
            }
        }

    发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法:

     /**
         * A factory function that generates, defines and returns the proxy class given
         * the ClassLoader and array of interfaces.
         */
        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) {
                    // if no non-public proxy interfaces, use com.sun.proxy package
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 */
                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());
                }
            }
        }

    通过看代码终于找到了重点:

    //生成字节码
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

    那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:

    package jiankunking;
    
    import sun.misc.ProxyGenerator;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理演示
     */
    public class DynamicProxyDemonstration
    {
        public static void main(String[] args)
        {
            //代理的真实对象
            Subject realSubject = new RealSubject();
    
            /**
             * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
             * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
             * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
             */
            InvocationHandler handler = new InvocationHandlerImpl(realSubject);
    
            ClassLoader loader = handler.getClass().getClassLoader();
            Class[] interfaces = realSubject.getClass().getInterfaces();
            /**
             * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
             */
            Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
    
            System.out.println("动态代理对象的类型:"+subject.getClass().getName());
    
            String hello = subject.SayHello("jiankunking");
            System.out.println(hello);
            // 将生成的字节码保存到本地,
            createProxyClassFile();
        }
        private static void createProxyClassFile(){
            String name = "ProxySubject";
            byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
            FileOutputStream out =null;
            try {
                out = new FileOutputStream(name+".class");
                System.out.println((new File("hello")).getAbsolutePath());
                out.write(data);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(null!=out) try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }

    可以看一下这里代理对象的类型:

    我们用jd-jui 工具将生成的字节码反编译:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    import jiankunking.Subject;
    
    public final class ProxySubject
      extends Proxy
      implements Subject
    {
      private static Method m1;
      private static Method m3;
      private static Method m4;
      private static Method m2;
      private static Method m0;
      
      public ProxySubject(InvocationHandler paramInvocationHandler)
      {
        super(paramInvocationHandler);
      }
      
      public final boolean equals(Object paramObject)
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String SayGoodBye()
      {
        try
        {
          return (String)this.h.invoke(this, m3, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String SayHello(String paramString)
      {
        try
        {
          return (String)this.h.invoke(this, m4, new Object[] { paramString });
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String toString()
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final int hashCode()
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
          m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    }

    这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,也就是说:

    Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

    这里的subject实际是这个类的一个实例,那么我们调用它的:

    public final String SayHello(String paramString)

    就是调用我们定义的InvocationHandlerImpl的 invoke方法:

    ======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================

    五、结论

    到了这里,终于解答了:
    subject.SayHello("jiankunking")这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?
    因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,
    在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。
    包含生成本地class文件的demo:
    http://download.csdn.net/detail/xunzaosiyecao/9597474
    https://github.com/JianKunKing/DynamicProxyDemo
    通过分析代码可以看出Java 动态代理,具体有如下四步骤:

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

    个人微信公众号:

    作者:jiankunking 出处:http://blog.csdn.net/jiankunking

    本文参考过:

    http://www.2cto.com/kf/201608/533663.html

    http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

     

    展开全文
  • 1.什么是动态代理? 答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的...

    1.什么是动态代理?
    答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
    2.为什么使用动态代理?
    答:因为动态代理可以对请求进行任何处理
    3.使用它有哪些好处?
    答:因为动态代理可以对请求进行任何处理
    4.哪些地方需要动态代理?
    答:不允许直接访问某些类;对访问要做特殊处理等
     
    目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 
    Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
    以下为模拟案例,通过动态代理实现在方法调用前后向控制台输出两句字符串


    下面是testPorject的结构



    首先定义一个DAO接口

    IUserDao

    package org.zhy.demo.proxy.Dao;
    
    public interface IUserDao {
    
    	public void addUser(String name, int age);
    }
    

    DAO接口只定义了一个addUser的方法,DAO的实现类负责实现对数据库的添加操作

    IUserDaoImpl

    package org.zhy.demo.proxy.Dao.Impl;
    
    import org.zhy.demo.proxy.Dao.IUserDao;
    
    public class IUserDaoImpl implements IUserDao {
    
    	/**
    	 * 这里模拟数据库操作 只打印信息
    	 */
    	@Override
    	public void addUser(String name, int age) {
    		System.out.println("开始添加user");
    		System.out.println("NAME:"+name);
    		System.out.println("AGE:"+age);
    		System.out.println("user添加完成");
    	}
    
    }
    


    添加一个新的包:org.zhy.demo.proxy.invocation

    添加一个新的类:MyInvocationHandler

    package org.zhy.demo.proxy.invocation;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 代理类,需要实现InvocationHandler接口
     * @author Administrator
     *
     */
    public class MyInvocationHandler implements InvocationHandler {
    
    	//定义一个私有变量,被代理的对象
    	private Object setter;
    
    	public Object getSetter() {
    		return setter;
    	}
    
    	public void setSetter(Object setter) {
    		this.setter = setter;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		this.startProxy();  //在方法执行之前执行代理方法
    		method.invoke(setter, args);  //执行被代理对象的方法
    		this.endProxy();//同时 在方法结束的时候也执行一下代理方法
    		return null;
    	}
    	
    	/**
    	 * 定义两个代理方法
    	 */
    	private void startProxy() {
    		System.out.println("开始执行代理方法");
    	}
    
    	private void endProxy() {
    		System.out.println("执行代理方法结束");
    	}
    
    }
    


    下面是具体实现:

    UserService

    package org.zhy.demo.proxy.service;
    
    import java.lang.reflect.Proxy;
    
    import org.zhy.demo.proxy.Dao.IUserDao;
    import org.zhy.demo.proxy.Dao.Impl.IUserDaoImpl;
    import org.zhy.demo.proxy.invocation.MyInvocationHandler;
    
    public class UserService {
    
    	public static void main(String[] args) {
    		IUserDao userDao = new IUserDaoImpl();  //实例化一个userDao
    		MyInvocationHandler myInvocationHandler = new MyInvocationHandler();  //实例化自己的代理类
    		myInvocationHandler.setSetter(userDao);  //被代理的对象
    		IUserDao dao = (IUserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), myInvocationHandler);  //定义一个新的代理
    		dao.addUser("张三", 23);  //执行dao的方法
    	}
    }
    


    执行结果


    展开全文
  • java动态代理

    万次阅读 2020-12-14 17:59:02
    最近在看一些技术源码的时候,发现很多地方都是动态代理, 真可谓是一切皆代理啊,所以我们需要弄明白代理模式这样在看源码的时候会好受很多。 2、基本概念 代理(Proxy)模式提供了间接访问目标对象的方式,即通过...
  • Java动态代理类实现日志简单实例

    千次阅读 2016-07-01 07:17:41
    开心一笑上课呢,同桌撕了一片纸...提出问题Java动态代理类实现简单的日志解决问题假如你已经有一定的java基础 假如你已经知道什么是动态代理。1.假如下面是真实的业务类及其实现类package com.hwy.test;/** * Create
  • JDK代理代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代理。答案是可以的,Mybatis就是这样的。 Mybatis使用JDK动态代理来实现Mapper接口,事先保存好Mapper接口,和接口声明...
  • Java动态代理实现

    千次阅读 2018-12-05 16:42:07
    java动态代理机制中,有两个重要的和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个和接口是实现我们动态代理所必须用到的。 下面先贴上代码: 首先需要一个接口: /* *...
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解...CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法代理final对象与final方法。(final类型不能有子类,final方法不能被重载)
  • 四、动态代理的JDK实现原理 4.1核心/接口 4.2 代理类$Proxy0解析 4.3 动态代理的经典使用五、手写代码模拟JDK动态代理六、参考资料项目源码已经上传,欢迎点击下载~先将自己总结的Java动态代理UML图放在前面,...
  • 代理模式及Java实现动态代理

    千次阅读 2016-12-18 18:25:13
    代理模式 定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原...Subject 是委托对象和代理对象都共同实现的接口。Request() 是委托对象和代理对象共同拥有的方法。 要理解
  • 上篇介绍了一下静态代理Java中的代理模式——静态代理以及分析静态代理的缺点 也分析了一下静态代理的缺点: 1、由于静态代理中的代理类是针对某一个去做代理的,那么假设一个系统中有100个Service,则需要...
  • 轻松学,Java 中的代理模式及动态代理

    万次阅读 多人点赞 2017-06-29 22:08:55
    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。...
  • 大家在看java设计模式之 代理模式这篇文章的时候, 可以发现动态代理无非就是以下四个步骤,我们完全可以自己模拟实现。因为java的class文件格式是公开的,只要最终生成的class格式正确并且可以加载到JVM中我们就...
  • java动态代理实现

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

    千次阅读 2015-07-10 21:08:26
    上篇讲了:java动态代理浅析 这篇讲讲其内部实现原理。 1、相关的和接口 1.1 java.lang.reflect.Proxy 这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。 Proxy 的...
  • 1、动态代理的原理 ...Java提供2中动态代理的方式,一种是基于接口实现(JDK动态代理),一种是基于继承实现(Cglib)。 2、基于接口的动态代理模式 JDK代理模式中,有两个重要的点;一个(Proxy)和一个...
  • Java 动态代理-Jdk动态代理

    千次阅读 2019-08-27 16:24:41
    javajava.lang.reflect 包下提供了一个Proxy 和 InvocationHandler 接口来支持生产Jdk 动态代理类(不常用)或***动态代理对象***. 在普通的企业开发中, 通常是不会涉及到动态代理开发的, 但是若是开发框架或做底层...
  • java动态代理实现接口调用

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

    万次阅读 2019-12-09 18:14:20
    java代理:在不用修改源码的情况下,可以在实现类方法的前后做些额外的处理。 1)、静态代理。 在程序运行前,代理类的.class文件已存在。事先知道要代理实现类是什么。 优点:不需要知道委托类(实现类),只...
  • Java动态代理

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

    万次阅读 多人点赞 2018-07-24 23:42:58
    为了保持行为的一致性,代理类和委托通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托对象的直接访问,也可以很好地隐藏和保护委托...
  • Java中自带的动态代理InvocationHandler接口、Proxy只能针对接口进行动态代理,如果要对进行代理可以使用第三方的类库像CGLIG等相关对字节码操作实现的类库; 下面我们可以看一下使用Java动态代理代理类会发生...
  • Java实现动态代理示例

    千次阅读 2018-08-15 10:38:16
    首先定义一个接口 public interface IStars { void sing(); void dance();...然后定义一个star实现这个接口 public class Stars implements IStars { private String name; publ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 321,923
精华内容 128,769
关键字:

java无实现类动态代理

java 订阅