精华内容
参与话题
问答
  • Java 代理模式

    万次阅读 2017-09-25 09:00:40
    什么是代理代理是一种设计模式,它的核心思想,是将对目标的访问转移到代理对象上。这样做的好处就是,目标对象在不改变代码的情况下,可以通过代理对象加一些额外的功能。这是一种编程思想,在不改变原有代码的情况...

    转载请标明出处:
    http://blog.csdn.net/forezp/article/details/78081673
    本文出自方志朋的博客

    什么是代理

    代理是一种设计模式,它的核心思想,是将对目标的访问转移到代理对象上。这样做的好处就是,目标对象在不改变代码的情况下,可以通过代理对象加一些额外的功能。这是一种编程思想,在不改变原有代码的情况下,通过代理增加一些扩展功能。

    代理过程如图所示,用户访问代理对象,代理对象通过访问目标对象,来达到用户访问目标对象的目的,

    在这里插入图片描述

    代理模式包含一下三个角色:

    • ISubject:接口对象,该接口是对象和它的代理共用的接口。
    • TargetSubject:目标对象,是实现抽象主题接口的类。
    • Proxy:代理角色,内部含有对目标对象TargetSubject的引用,从而可以操作真实对象。代理对象提供与目标对象相同的接口,以便在任何时刻都能代替目标对象。同时,代理对象可以在执行目标对象操作时,附加其他的操作,相当于对真实对象进行封装。

    常见的代理模式分为静态代理和动态代理,动态代理在Java中的实现分为JDK动态代理和cglib代理。

    静态代理

    在之前已经说过,在代理模式中有三个角色,一是目标接口,二是目标对象,三是代理对象。

    现在以具体代码来实现,首先是目标接口如下:

     public interface IBlogService {
    
        void writeBlog();
    }
    
    

    目标对象实现了目标接口,代码如下:

    public class BlogService implements IBlogService {
    
        @Override
        public void writeBlog() {
            System.out.println("i'm writing...");
        }
    }
    
    
    

    静态代理对象,通过构造方法获取到目标对象,并实现了目标接口,在目标接口的方法里调用了目标对象的方法,代码如下:

    public class BlogStaticProxy implements IBlogService{
        private IBlogService blogService;
    
        public BlogStaticProxy(IBlogService blogService) {
            this.blogService = blogService;
        }
    
    
    
        @Override
        public void writeBlog() {
            System.out.println("start writing...");
            blogService.writeBlog();
            System.out.println("end writing...");
        }
    }
    
    
    

    测试:

    public class TestStaticProxy {
    
        public static void main(String[] args) {
            IBlogService target = new BlogService();
            BlogStaticProxy proxy = new BlogStaticProxy(target);
            proxy.write();
        }
    }
    

    start writing…

    i’m writing…

    end writing…

    静态代理,在不修改目标对象的情况下,可以通过代理对象做额外的扩展功能。但静态方法不是很灵活,如果目标接口的代码修改,目标对象和代理对象都需要修改。

    动态代理在一定程度上避免这种情况,动态代理不需要代理对象实现目标接口,并且上在java 虚拟机的内存中动态的生成代理对象

    Jdk动态对象

    Jdk的动态代理由Proxy这个类来生成,它有三个参数:

    • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的
    • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型
    • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
     public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
        
        }
    
    

    Jdk的动态代理代码如下:

     public class JdkBlogProxyFactory {
    
        private Object target;
    
        public JdkBlogProxyFactory(Object target) {
            this.target = target;
        }
    
        public Object newInstance() {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    (proxy, method, args) -> {
                        System.out.println("start writing");
                        Object o = method.invoke(target, args);
                        System.out.println("end writing");
                        return o;
                    });
        }
    }
    
    

    测试类:

    public class TestJdkProxy {
        public static void main(String[] args) {
    
            IBlogService target = new BlogService();
    
            System.out.println(target.getClass());
    
            // 给目标对象,创建代理对象
            IBlogService proxy = (IBlogService) new JdkBlogProxyFactory(target).newInstance();
            // class $Proxy0   内存中动态生成的代理对象
            System.out.println(proxy.getClass());
    
            // 执行方法   【代理对象】
            proxy.writeBlog();
        }
    }
    
    
    

    控制台打印如下:

    class com.forezp.proxy.BlogService
    class com.sun.proxy.$Proxy0
    start writing
    i'm writing...
    end writing
    
    

    CGLib动态代理

    CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

    CglibBlogFactory代理工厂类如下:

    public class CglibBlogFactory implements MethodInterceptor {
    
        private Object target;
    
        public CglibBlogFactory(Object target) {
            this.target = target;
        }
    
        //给目标对象创建一个代理对象
        public Object getProxyInstance() {
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(target.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.创建子类(代理对象)
            return en.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("start writing...");
            //执行目标对象的方法
            Object returnValue = method.invoke(target, objects);
            System.out.println("end writing...");
            return returnValue;
        }
    }
    
    

    测试类:

    public class TestCglib {
    
        public static void main(String[] args) {
            IBlogService target = new BlogService();
            //代理对象
            IBlogService proxy = (IBlogService) new CglibBlogFactory(target).getProxyInstance();
            //执行代理对象的方法
            proxy.writeBlog();
        }
    }
    
    

    运行程序,控制台打印:

    start writing...
    i'm writing...
    end writing...
    
    

    参考资料

    http://www.cnblogs.com/cenyu/p/6289209.html

    http://blog.csdn.net/yakoo5/article/details/9099133/

    更多阅读

    史上最简单的 SpringCloud 教程汇总

    SpringBoot教程汇总

    Java面试题系列汇总

    关注我

    SouthEast
    扫码关注公众号有惊喜

    (转载本站文章请注明作者和出处 方志朋的博客

    展开全文
  • 轻松学,Java 中的代理模式及动态代理

    万次阅读 多人点赞 2017-06-29 22:08:55
    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。...

    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。

    我们先来分析代理这个词。

    代理

    代理是英文 Proxy 翻译过来的。我们在生活中见到过的代理,大概最常见的就是朋友圈中卖面膜的同学了。

    她们从厂家拿货,然后在朋友圈中宣传,然后卖给熟人。

    这里写图片描述

    按理说,顾客可以直接从厂家购买产品,但是现实生活中,很少有这样的销售模式。一般都是厂家委托给代理商进行销售,顾客跟代理商打交道,而不直接与产品实际生产者进行关联。

    所以,代理就有一种中间人的味道。

    接下来,我们说说软件中的代理模式。

    代理模式

    代理模式是面向对象编程中比较常见的设计模式。
    这里写图片描述

    这是常见代理模式常见的 UML 示意图。

    需要注意的有下面几点:

    1. 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
    2. 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
    3. 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
    4. 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。

    如果难于理解的话,我用事例说明好了。值得注意的是,代理可以分为静态代理和动态代理两种。先从静态代理讲起。

    静态代理

    我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?

    电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始结束时播放一些广告。

    现在用代码来进行模拟。

    首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。

    
    package com.frank.test;
    
    public interface Movie {
    	void play();
    }
    
    

    然后,我们要有一个真正的实现这个 Movie 接口的类,和一个只是实现接口的代理类。

    package com.frank.test;
    
    public class RealMovie implements Movie {
    
    	@Override
    	public void play() {
    		// TODO Auto-generated method stub
    		System.out.println("您正在观看电影 《肖申克的救赎》");
    	}
    
    }
    

    这个表示真正的影片。它实现了 Movie 接口,play() 方法调用时,影片就开始播放。那么 Proxy 代理呢?

    package com.frank.test;
    
    public class Cinema implements Movie {
    	
    	RealMovie movie;
    	
    	public Cinema(RealMovie movie) {
    		super();
    		this.movie = movie;
    	}
    
    
    	@Override
    	public void play() {
    		
    		guanggao(true);
    		
    		movie.play();
    		
    		guanggao(false);
    	}
    	
    	public void guanggao(boolean isStart){
    		if ( isStart ) {
    			System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");
    		} else {
    			System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");
    		}
    	}
    
    }
    
    

    Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。现在,我们编写测试代码。

    package com.frank.test;
    
    public class ProxyTest {
    
    	public static void main(String[] args) {
    		
    		RealMovie realmovie = new RealMovie();
    		
    		Movie movie = new Cinema(realmovie);
    		
    		movie.play();
    
    	}
    
    }
    
    

    然后观察结果:

    电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!
    您正在观看电影 《肖申克的救赎》
    电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!
    
    

    现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

    上面介绍的是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的,比如上面代码中的 Cinema 这个类。下面要介绍的内容就是动态代理。

    动态代理

    既然是代理,那么它与静态代理的功能与目的是没有区别的,唯一有区别的就是动态与静态的差别。

    那么在动态代理的中这个动态体现在什么地方?

    上一节代码中 Cinema 类是代理,我们需要手动编写代码让 Cinema 实现 Movie 接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Movie 接口的代理,而不需要去定义 Cinema 这个类。这就是它被称为动态的原因。

    也许概念比较抽象。现在实例说明一下情况。

    假设有一个大商场,商场有很多的柜台,有一个柜台卖茅台酒。我们进行代码的模拟。

    package com.frank.test;
    
    public interface SellWine {
    	
    	 void mainJiu();
    
    }
    

    SellWine 是一个接口,你可以理解它为卖酒的许可证。

    package com.frank.test;
    
    public class MaotaiJiu implements SellWine {
    
    	@Override
    	public void mainJiu() {
    		// TODO Auto-generated method stub
    		System.out.println("我卖得是茅台酒。");
    
    	}
    
    }
    
    

    然后创建一个类 MaotaiJiu,对的,就是茅台酒的意思。

    我们还需要一个柜台来卖酒:

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    
    public class GuitaiA implements InvocationHandler {
    	
    	private Object pingpai;
    	
    	
    	public GuitaiA(Object pingpai) {
    		this.pingpai = pingpai;
    	}
    
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());
    		method.invoke(pingpai, args);
    		System.out.println("销售结束");
    		return null;
    	}
    
    }
    
    

    GuitaiA 实现了 InvocationHandler 这个类,这个类是什么意思呢?大家不要慌张,待会我会解释。

    然后,我们就可以卖酒了。

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    	
    		dynamicProxy.mainJiu();
    			
    	}
    
    }
    
    
    

    这里,我们又接触到了一个新的概念,没有关系,先别管,先看结果。

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    
    

    看到没有,我并没有像静态代理那样为 SellWine 接口实现一个代理类,但最终它仍然实现了相同的功能,这其中的差别,就是之前讨论的动态代理所谓“动态”的原因。

    动态代理语法

    放轻松,下面我们开始讲解语法,语法非常简单。

    动态代码涉及了一个非常重要的类 Proxy。正是通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。

    Proxy

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

    下面讲解它的 3 个参数意义。

    • loader 自然是类加载器
    • interfaces 代码要用来代理的接口
    • h 一个 InvocationHandler 对象

    初学者应该对于 InvocationHandler 很陌生,我马上就讲到这一块。

    InvocationHandler

    InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。

    public interface InvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    
    

    InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

    • proxy 代理对象
    • method 代理对象调用的方法
    • args 调用的方法中的参数

    因为,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者。

    public class GuitaiA implements InvocationHandler {
    	
    	private Object pingpai;
    	
    	
    	public GuitaiA(Object pingpai) {
    		this.pingpai = pingpai;
    	}
    
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());
    		method.invoke(pingpai, args);
    		System.out.println("销售结束");
    		return null;
    	}
    
    }
    
    

    GuitaiA 就是实际上卖酒的地方。

    现在,我们加大难度,我们不仅要卖茅台酒,还想卖五粮液

    package com.frank.test;
    
    public class Wuliangye implements SellWine {
    
    	@Override
    	public void mainJiu() {
    		// TODO Auto-generated method stub
    		System.out.println("我卖得是五粮液。");
    
    	}
    
    }
    
    

    Wuliangye 这个类也实现了 SellWine 这个接口,说明它也拥有卖酒的许可证,同样把它放到 GuitaiA 上售卖。

    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    	}
    
    }
    
    

    我们来看结果:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    
    

    有人会问,dynamicProxy 和 dynamicProxy1 什么区别没有?他们都是动态产生的代理,都是售货员,都拥有卖酒的技术证书。

    我现在扩大商场的经营,除了卖酒之外,还要卖烟。

    首先,同样要创建一个接口,作为卖烟的许可证。

    package com.frank.test;
    
    public interface SellCigarette {
    	void sell();
    }
    
    

    然后,卖什么烟呢?我是湖南人,那就芙蓉王好了。

    public class Furongwang implements SellCigarette {
    
    	@Override
    	public void sell() {
    		// TODO Auto-generated method stub
    		System.out.println("售卖的是正宗的芙蓉王,可以扫描条形码查证。");
    	}
    
    }
    
    

    然后再次测试验证:

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		Furongwang fu = new Furongwang();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		InvocationHandler jingxiao3 = new GuitaiA(fu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    		SellCigarette dynamicProxy3 = (SellCigarette) Proxy.newProxyInstance(Furongwang.class.getClassLoader(),
    				Furongwang.class.getInterfaces(), jingxiao3);
    		
    		dynamicProxy3.sell();
    		
    	}
    
    }
    
    

    然后,查看结果:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    销售开始  柜台是: GuitaiA
    售卖的是正宗的芙蓉王,可以扫描条形码查证。
    销售结束
    
    
    

    结果符合预期。大家仔细观察一下代码,同样是通过 Proxy.newProxyInstance() 方法,却产生了 SellWine 和 SellCigarette 两种接口的实现类代理,这就是动态代理的魔力。

    动态代理的秘密

    一定有同学对于为什么 Proxy 能够动态产生不同接口类型的代理感兴趣,我的猜测是肯定通过传入进去的接口然后通过反射动态生成了一个接口实例。
    比如 SellWine 是一个接口,那么 Proxy.newProxyInstance() 内部肯定会有

    
    new SellWine();
    

    这样相同作用的代码,不过它是通过反射机制创建的。那么事实是不是这样子呢?直接查看它们的源码好了。需要说明的是,我当前查看的源码是 1.8 版本。

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
    
    
            /*
             * Look up or generate the designated proxy class.
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
    
    
                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);
            }
        }
    
    
    

    newProxyInstance 的确创建了一个实例,它是通过 cl 这个 Class 文件的构造方法反射生成。cl 由 getProxyClass0() 方法获取。

    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);
    }
    
    

    直接通过缓存获取,如果获取不到,注释说会通过 ProxyClassFactory 生成。

    /**
         * 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<?>>
        {
            // Proxy class 的前缀是 “$Proxy”,
            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());
                }
            }
        }
    
    
    

    这个类的注释说,通过指定的 ClassLoader 和 接口数组 用工厂方法生成 proxy class。 然后这个 proxy class 的名字是:

    
    // Proxy class 的前缀是 “$Proxy”,
    private static final String proxyClassNamePrefix = "$Proxy";
    
    long num = nextUniqueNumber.getAndIncrement();
    
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
    

    所以,动态生成的代理类名称是包名+$Proxy+id序号

    生成的过程,核心代码如下:

    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
    
             
    return defineClass0(loader, proxyName,
                        proxyClassFile, 0, proxyClassFile.length);
    
    

    这两个方法,我没有继续追踪下去,defineClass0() 甚至是一个 native 方法。我们只要知道,动态创建代理这回事就好了。

    现在我们还需要做一些验证,我要检测一下动态生成的代理类的名字是不是包名+$Proxy+id序号

    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		Furongwang fu = new Furongwang();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		InvocationHandler jingxiao3 = new GuitaiA(fu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    		SellCigarette dynamicProxy3 = (SellCigarette) Proxy.newProxyInstance(Furongwang.class.getClassLoader(),
    				Furongwang.class.getInterfaces(), jingxiao3);
    		
    		dynamicProxy3.sell();
    		
    		System.out.println("dynamicProxy class name:"+dynamicProxy.getClass().getName());
    		System.out.println("dynamicProxy1 class name:"+dynamicProxy1.getClass().getName());
    		System.out.println("dynamicProxy3 class name:"+dynamicProxy3.getClass().getName());
    		
    	}
    
    }
    
    

    结果如下:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    销售开始  柜台是: GuitaiA
    售卖的是正宗的芙蓉王,可以扫描条形码查证。
    销售结束
    
    dynamicProxy class name:com.sun.proxy.$Proxy0
    dynamicProxy1 class name:com.sun.proxy.$Proxy0
    dynamicProxy3 class name:com.sun.proxy.$Proxy1
    
    

    SellWine 接口的代理类名是:com.sun.proxy.$Proxy0
    SellCigarette 接口的代理类名是:com.sun.proxy.$Proxy1

    这说明动态生成的 proxy class 与 Proxy 这个类同一个包。

    下面用一张图让大家记住动态代理涉及到的角色。
    这里写图片描述
    红框中 $Proxy0就是通过 Proxy 动态生成的。
    $Proxy0实现了要代理的接口。
    $Proxy0通过调用 InvocationHandler来执行任务。

    代理的作用

    可能有同学会问,已经学习了代理的知识,但是,它们有什么用呢?

    主要作用,还是在不修改被代理对象的源码上,进行功能的增强。

    这在 AOP 面向切面编程领域经常见。

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    主要功能
    日志记录,性能统计,安全控制,事务处理,异常处理等等。

    上面的引用是百度百科对于 AOP 的解释,至于,如何通过代理来进行日志记录功能、性能统计等等,这个大家可以参考 AOP 的相关源码,然后仔细琢磨。

    同注解一样,很多同学可能会有疑惑,我什么时候用代理呢?

    这取决于你自己想干什么。你已经学会了语法了,其他的看业务需求。对于实现日志记录功能的框架来说,正合适。

    至此,静态代理和动态代理者讲完了。

    总结

    1. 代理分为静态代理和动态代理两种。
    2. 静态代理,代理类需要自己编写代码写成。
    3. 动态代理,代理类通过 Proxy.newInstance() 方法生成。
    4. 不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。
    5. 静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。
    6. 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。
    7. 代理模式本质上的目的是为了增强现有代码的功能。

    读者们都在下面的二维码所示的免费的知识星球问我问题:
    在这里插入图片描述

    展开全文
  • 秒懂Java代理与动态代理模式

    万次阅读 多人点赞 2018-06-30 17:08:23
    什么是代理模式?解决什么问题(即为什么需要)?什么是静态代理?什么是动态代理模式?二者什么关系?具体如何实现?什么原理?如何改进?这即为我们学习一项新知识的正确打开方式,我们接下来会以此展开,让你秒懂...

    版权申明】非商业目的可自由转载
    博文地址:https://blog.csdn.net/shusheng0007/article/details/80864854
    出自:shusheng007

    设计模式系列文章:
    秒懂设计模式之建造者模式(Builder Pattern)
    秒懂设计模式之简单工厂模式(Simple Factory Pattern)
    秒懂设计模式之工厂方法模式(Factory Method Pattern)
    秒懂设计模式之抽象工厂模式(Abstract Factory Pattern)

    概述

    什么是代理模式?解决什么问题(即为什么需要)?什么是静态代理?什么是动态代理模式?二者什么关系?具体如何实现?什么原理?如何改进?这即为我们学习一项新知识的正确打开方式,我们接下来会以此展开,让你秒懂。

    概念

    什么是代理模式

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

    定义总是抽象而晦涩难懂的,让我们回到生活中来吧。

    实例:王二狗公司(天津在线回声科技发展有限公司)老板突然在发工资的前一天带着小姨子跑路了,可怜二狗一身房贷,被迫提起劳动仲裁,劳动局就会为其指派一位代理律师全权负责二狗的仲裁事宜。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理王二狗。

    解决什么问题

    下面是一些使用场景,不过太抽象,暂时可以不要在意,随着你的不断进步你终究会明白的。

    • 远程代理 :为位于两个不同地址空间对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提高系统的整体运行效率。
    • 虚拟代理:通过一个消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销。
    • 缓冲代理:为某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,优化系统性能,缩短执行时间。
    • 保护代理:可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。
    • 智能引用:要为一个对象的访问(引用)提供一些额外的操作时可以使用

    什么是静态代理

    静态代理是指预先确定了代理与被代理者的关系,例如王二狗的代理律师方文镜是在开庭前就确定的了。那映射到编程领域的话,就是指代理类与被代理类的依赖关系在编译期间就确定了。下面就是王二狗劳动仲裁的代码实现:

    首先定义一个代表诉讼的接口

    public interface ILawSuit {
        void submit(String proof);//提起诉讼
        void defend();//法庭辩护
    }
    

    王二狗诉讼类型,实现ILawSuit接口

    public class SecondDogWang implements ILawSuit {
        @Override
        public void submit(String proof) {
            System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
        }
    
        @Override
        public void defend() {
            System.out.println(String.format("铁证如山,%s还钱","马旭"));
        }
    }
    

    代理律师诉讼类,实现ILawSuit接口

    public class ProxyLawyer implements ILawSuit {
    
        ILawSuit plaintiff;//持有要代理的那个对象
        public ProxyLawyer(ILawSuit plaintiff) {
            this.plaintiff=plaintiff;
        }
    
        @Override
        public void submit(String proof) {
            plaintiff.submit(proof);
        }
    
        @Override
        public void defend() {
            plaintiff.defend();
        }
    }
    

    产生代理对象的静态代理工厂类

    public class ProxyFactory {
        public static ILawSuit getProxy(){
            return new ProxyLawyer(new SecondDogWang());
        }
    }
    

    这样就基本构建了静态代理关系了,然后在客户端就可以使用代理对象来进行操作了。

        public static void main(String[] args) {
            ProxyFactory.getProxy().submit("工资流水在此");
            ProxyFactory.getProxy().defend();
        }
    

    输出结果如下:

    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还钱
    

    可以看到,代理律师全权代理了王二狗的本次诉讼活动。那使用这种代理模式有什么好处呢,我们为什么不直接让王二狗直接完成本次诉讼呢?现实中的情况比较复杂,但是我可以简单列出几条:这样代理律师就可以在提起诉讼等操作之前做一些校验工作,或者记录工作。例如二狗提供的资料,律师可以选择的移交给法庭而不是全部等等操作,就是说可以对代理的对做一些控制。例如二狗不能出席法庭,代理律师可以代为出席。。。

    什么是动态代理

    动态代理本质上仍然是代理,情况与上面介绍的完全一样,只是代理与被代理人的关系是动态确定的,例如王二狗的同事牛翠花开庭前没有确定她的代理律师,而是在开庭当天当庭选择了一个律师,映射到编程领域为这个关系是在运行时确定的。

    那既然动态代理没有为我们增强代理方面的任何功能,那我们为什么还要用动态代理呢,静态代理不是挺好的吗?凡是动态确定的东西大概都具有灵活性,强扩展的优势。上面的例子中如果牛翠花也使用静态代理的话,那么就需要再添加两个类。一个是牛翠花诉讼类,一个是牛翠花的代理律师类,还的在代理静态工厂中添加一个方法。而如果使用动态代理的话,就只需要生成一个诉讼类就可以了,全程只需要一个代理律师类,因为我们可以动态的将很多人的案子交给这个律师来处理。

    Jdk动态代理实现

    在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。

    InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。

    接下来我们看下实例,牛翠花动态指定代理律师是如何实现的。
    1.构建一个牛翠花诉讼类

    public class CuiHuaNiu implements ILawSuit {
        @Override
        public void submit(String proof) {
            System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
        }
        @Override
        public void defend() {
            System.out.println(String.format("铁证如山,%s还牛翠花血汗钱","马旭"));
        }
    }
    

    2.构建一个动态代理类

    public class DynProxyLawyer implements InvocationHandler {
        private Object target;//被代理的对象
        public DynProxyLawyer(Object obj){
            this.target=obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	    System.out.println("案件进展:"+method.getName());
            Object result=method.invoke(target,args);
            return result;
        }
    }
    

    3.修改静态工厂方法

    public class ProxyFactory {
    	...
    
        public static Object getDynProxy(Object target) {
            InvocationHandler handler = new DynProxyLawyer(target);
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
        }
    }
    

    4.客户端使用

        public static void main(String[] args) {
            ILawSuit proxy= (ILawSuit) ProxyFactory.getDynProxy(new CuiHuaNiu());
            proxy.submit("工资流水在此");
            proxy.defend();
        }
    

    输出结果为:

    案件进展:submit
    老板欠薪跑路,证据如下:工资流水在此
    案件进展:defend
    铁证如山,马旭还牛翠花血汗钱
    

    JDK动态代理实现的原理

    首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    

    此方法的参数含义如下
    proxy:代表动态代理对象
    method:代表正在执行的方法
    args:代表当前执行方法传入的实参
    返回值:表示当前执行方法的返回值

    例如上面牛翠花案例中,我们使用Proxy类的newProxyInstance()方法生成的代理对象proxy去调用了proxy.submit("工资流水在此");操作,那么系统就会将此方法分发给invoke().其中proxy对象的类是系统帮我们动态生产的,其实现了我们的业务接口ILawSuit

    cgLib的动态代理实现

    由于JDK只能针对实现了接口的类做动态代理,而不能对没有实现接口的类做动态代理,所以cgLib横空出世!CGLib(Code Generation Library)是一个强大、高性能的Code生成类库,它可以在程序运行期间动态扩展类或接口,它的底层是使用java字节码操作框架ASM实现。

    1 引入cgLib 库
    cglib-nodep-3.2.6.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.

    2 定义业务类,被代理的类没有实现任何接口

    public class Frank {
       public void submit(String proof) {
           System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
       }
       public void defend() {
           System.out.println(String.format("铁证如山,%s还Frank血汗钱","马旭"));
       }
    }
    

    3 定义拦截器,在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。

    public class cgLibDynProxyLawyer implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
            if (method.getName().equals("submit"))
                System.out.println("案件提交成功,证据如下:"+ Arrays.asList(params));
            Object result = methodProxy.invokeSuper(o, params);
            return result;
        }
    }
    

    4定义动态代理工厂,生成动态代理

    public class ProxyFactory {
        public static Object getGcLibDynProxy(Object target){
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(new cgLibDynProxyLawyer());
            Object targetProxy= enhancer.create();
            return targetProxy;
        }
    }
    

    5客户端调用

      public static void main(String[] args) {
            Frank cProxy= (Frank) ProxyFactory.getGcLibDynProxy(new Frank());
            cProxy.submit("工资流水在此");
            cProxy.defend();
        }
    

    输出结果:

    案件提交成功,证据如下:[工资流水在此]
    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还Frank血汗钱
    

    可见,通过cgLib对没有实现任何接口的类做了动态代理,达到了和前面一样的效果。这里只是简单的讲解了一些cgLib的使用方式,有兴趣的可以进一步了解其比较高级的功能,例如回调过滤器(CallbackFilter)等。

    cgLib的动态代理原理

    CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

    CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    CGLIB缺点:对于final方法,无法进行代理。

    动态代理在AOP中的应用

    什么是AOP? 维基百科上如是说:

    定义:In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.
    AOP是一种编程范式,其目标是通过隔离切面耦合来增加程序的模块化。

    首先声明,AOP是OOP的补充,其地位及其重要性远不及OOP,总体来说OOP面向名词领域而AOP面向动词领域,例如对一个人的设计肯定是使用OOP,例如这个人有手,脚,眼睛瞪属性。而对这个人上厕所这个动作就会涉及到AOP,例如上厕所前的先确定一下拿没拿手纸等。要理解AOP就首先要理解什么是切面耦合(cross-cutting concerns)。例如有这样一个需求,要求为一个程序中所有方法名称以test开头的方法打印一句log,这个行为就是一个典型的cross-cutting场景。首先这个打印log和业务毫无关系,然后其处于分散在整个程序当中的各个模块,如果按照我们原始的方法开发,一旦后期需求变动将是及其繁琐的。所以我们就需要将这个切面耦合封装隔离,不要将其混入业务代码当中。

    例如在王二狗的案子中,我们希望在案子起诉后打印一句成功的log,如果不使用代理的话,我们是需要将log写在相应的业务逻辑里面的,例如王二狗诉讼类SecondDogWang里面的submit()方法中。使用了动态代理后,我们只需要在InvocationHandler 里面的invoke()方法中写就可以了,不会侵入业务代码当中,在以后的维护过程中对业务毫无影响,这是我们希望看到的。

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("submit"))
               System.out.println("案件提交成功,证据如下:"+ Arrays.asList(args));
        Object result=method.invoke(target,args);
        return result;
    }
    

    输出结果为:

    案件提交成功,证据如下:[工资流水在此]
    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还牛翠花血汗钱
    

    所以AOP主要可以用于:日志记录,性能统计,安全控制,事务处理,异常处理等场景下。

    总结

    静态代理比动态代理更符合OOP原则,在日常开发中使用也较多。动态代理在开发框架时使用较多,例如大名鼎鼎的Spring

    最后希望王二狗和牛翠花他们可以顺利拿回自己的血汗钱。

    展开全文
  • Java代理模式

    千次阅读 多人点赞 2019-01-14 22:10:07
    代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和目标类会实现同一接口或是派生自相同的父类。 1.1 ...

    代理模式

      23中(Gof)中代理模式中的一种,AOP本身就是基于动态代理实现的,所以掌握了代理模式对AOP的学习很有帮助,所以先讲下代理模式

    1.静态代理模式

      若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和目标类会实现同一接口或是派生自相同的父类。

    1.1 创建接口

    /**
    * 定义公共接口
    * @author dpb[波波烤鸭]
    *
    */
    public interface SomeService {
       String doSome();
    }
    

    1.2 创建接口实现类

    /**
    * 静态代理模式的实现类
    * @author dpb[波波烤鸭]
    *
    */
    public class SomeServiceImpl implements SomeService{
       @Override
       public String doSome() {
       	// TODO Auto-generated method stub
       	return "hello";
       }
    }
    

    1.3 创建静态代理类

    /**
    * 代理类
    *    增强实现类
    *    和实现类实现同一个接口
    * @author dpb[波波烤鸭]
    *
    */
    public class SomeProxy implements SomeService{
       private SomeService target;
       public SomeProxy(SomeService target) {
       	super();
       	this.target = target;
       }
       /**
        * 增强方法
        *    将返回结果转换为大写
        */
       @Override
       public String doSome() {
       	return target.doSome().toUpperCase();
       }
    }
    

    1.4 测试实现

       public static void main(String[] args) {
       	SomeService some = new SomeServiceImpl();
       	// 获取静态代理对象
       	SomeProxy proxy = new SomeProxy(some);
       	System.out.println(proxy.doSome());
       }
    

    在这里插入图片描述

    2.动态代理模式

      代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。

    代理类型 使用场景
    JDK动态代理 如果目标对象实现了接口,采用JDK的动态代理
    cglib动态代理 如果目标对象没有实现了接口,必须采用CGLIB动态代理

    2.1.JDK动态代理

    声明接口

    /**
     * 定义公共接口
     * @author dpb[波波烤鸭]
     *
     */
    public interface SomeService {
    	String doSome();
    }
    

    创建实现类

    /**
     * 静态代理模式的实现类
     * @author dpb[波波烤鸭]
     *
     */
    public class SomeServiceImpl implements SomeService{
    	@Override
    	public String doSome() {
    		// TODO Auto-generated method stub
    		return "hello";
    	}
    }
    

    JDK代理实现

    public static void main(String[] args) {
    	SomeService some = new SomeServiceImpl();
    	// 获取静态代理对象
    	SomeService proxy = (SomeService) Proxy.newProxyInstance(
    			some.getClass().getClassLoader() // 实现类的类加载器
    			, some.getClass().getInterfaces() // 实现类 实现的所有的接口
    			, new InvocationHandler()  // 处理器
    			{
    				/**
    				 * proxy 代理对象
    				 * method 目标的方法
    				 * args 目标方法的参数
    				 */
    				@Override
    				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    					String msg = (String) method.invoke(some, args);
    					return msg.toUpperCase();
    				}
    			});
    	System.out.println(proxy.doSome());
    
    }
    

    在这里插入图片描述

    2.2CGLIB动态代理

    导入cglib的jar包

    在这里插入图片描述

    创建目标类

    /**
     * 静态代理模式的实现类
     * @author dpb[波波烤鸭]
     *
     */
    public class SomeServiceImpl {
    	
    	public String doSome() {
    		// TODO Auto-generated method stub
    		return "hello";
    	}
    }
    

    创建cglib工厂

    /**
     * cglib代理类
     * @author dpb[波波烤鸭]
     *
     */
    public class CglibProxy implements MethodInterceptor{
    	
    	private SomeServiceImpl target;
    	
    	public CglibProxy(SomeServiceImpl target) {
    		this.target = target;
    	}
    
    	/**
    	 * 创建cglib代理对象的方法
    	 * @return
    	 */
    	public SomeServiceImpl createProxy(){
    		// 创建增强器
    		Enhancer e = new Enhancer();
    		// 指定父类
    		e.setSuperclass(SomeServiceImpl.class);
    		// 指定回调接口对象
    		e.setCallback(this);
    		// 创建cglib代理对象
    		return (SomeServiceImpl) e.create();
    	}
    
    	/**
    	 * 拦截方法
    	 */
    	@Override
    	public Object intercept(Object obj, Method method, Object[] agrs, MethodProxy proxy) throws Throwable {
    		String msg = (String)method.invoke(target, agrs);
    		return msg.toUpperCase();
    	}
    
    }
    
    

    测试

    public static void main(String[] args) {
    	// 定义目标对象
    	SomeServiceImpl some = new SomeServiceImpl();
    	// 获取代理对象
    	SomeServiceImpl proxy = new CglibProxy(some).createProxy();
    	System.out.println(proxy.doSome());
    }
    

    在这里插入图片描述

    展开全文
  • Java代理

    千次阅读 多人点赞 2018-08-11 00:50:06
    说说 JAVA 代理模式 原文出处: http://www.importnew.com/26116.html 事例 小张是一个普普通通的码农,每天勤勤恳恳地码代码。某天中午小张刚要去吃饭,一个电话打到了他的手机上。“是XX公司的小张吗?我是YY...
  • java 代理模式详解

    千次阅读 2018-08-03 20:34:58
    代理也称“委托”,分为静态代理和动态代理代理模式也是常用的设计模式之一,具有方法增强、高扩展性的设计优势。 代理的设计理念是限制对象的直接访问,即不能通过 new 的方式得到想要的对象,而是访问该对象的...
  • java技术——动态代理(cglib)

    万次阅读 2016-04-21 21:59:56
    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不...
  • java设计模式-代理模式

    万次阅读 2019-04-10 13:54:28
    需求(干什么):对明星唱歌的业务流程进行代理,而明星唱歌还是交由明星自己唱歌,这个流程把唱歌分成2部分了,1:歌手尽管唱歌,2:代理公司负责打杂(面谈,签合同,订票,收钱),对被代理的歌手来说,他解放了,相当于增强了,...
  • Java代理和动态代理机制分析和应用

    千次阅读 2015-12-02 19:54:54
    本博文中项目代码已开源下载地址:GitHubJava代理和动态代理机制分析和应用概述代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发...
  • Java动态代理

    千次阅读 2017-09-26 10:43:00
    代理模式: ...静态代理代理类是在编译时就实现好的,也就是说Java编译完成后代理类是一个实际的class文件 动态代理代理类是在运行时生成的,也就是说Java编译完之后并没有实际的class文件,而
  • java代理及动态代理

    千次阅读 2011-11-14 12:08:14
    代理java技术中起着很重要的作用,Spring的aop及各种开源框架都使用了代理的技术。 代理一般分为:静态代理与动态代理。 一、 静态代理,一般分为 类继承代理与对象组合代理。 类继承就是继承超类获得超类的功能...
  • java代理模式-原来你是这样的代理

    千次阅读 热门讨论 2017-03-26 23:15:03
    这几天在看一些框架源码时看到了一个很奇妙的设计模式,有种熟悉个感觉,一时想不出是什么模式,后面经过了解才知道是动态代理,就这样带着好奇心学习了这个模式,更深入了解代理会发现不仅有静态和动态,还有很多其他的...
  • java代理设置

    千次阅读 2018-09-06 09:43:46
    本文主要讲述使用HttpClient时的代理设置。 常见的设置代理的方法 使用系统代理配置 可以通过下面的方式来分别设置HTTP代理,HTTPS代理和SOCKS代理: // HTTP 代理,只能代理 HTTP 请求 System.setProperty...
  • java面试总结

    千次阅读 2019-07-06 12:40:58
    java面试总结java面试总结JDK有哪些实现代理方法?JDK动态代理和CGlib动态代理有什么区别?1.深入理解静态代理与JDK动态代理1.1 JDK动态代理为什么不支持类的代理?1.2 Java反射技术1.3 Java中Object的重写方法(基础...
  • java 代理demo

    千次阅读 2017-06-19 16:28:16
    public interface UserDAO { public void save(User u); } public class UserDAOImpl implements UserDAO { @Override public void save(User u) { System.out.println("a user saved!"); } ...
  • java代理模式

    千次阅读 2009-05-04 11:09:00
    1.代理模式代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式一般涉及到的...
  • java代理实现爬取代理IP

    万次阅读 2017-04-22 13:42:18
    使用java编写的,获取代理IP的java类,依赖很简单,就是jsoup和fastjson,直接运行main方法即可,易于嵌套到项目中使用
  • Java动态代理、cglib动态代理

    千次阅读 2016-02-24 14:17:57
    实现原理,利用Java代理模式,由一个代理类持有委托类的实例,并实现委托类一样的接口,来实现增强方法的目的。我们主要用它来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想...

空空如也

1 2 3 4 5 ... 20
收藏数 279,269
精华内容 111,707
关键字:

java代理

java 订阅