JAVA之代理模式

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

之前面试的过程中,有被面试官问到Spring中的AOP相关问题。当时只回答了具体的一个概念和相关应用,还补充了下底层是运用了代理模式;但之前一直并没有对相关的代理模式进行一个深入的理解,特此写下了这篇博客,记录下。。。


废话不多说,首先我们知道代理模式是设计模式中的一种,书中给到的定义是:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。网上通俗说是像我们生活中的中介。 举个例子:我要买房子,但我这个人没什么生活经验,我只懂得付钱

public class people{
     public void buy(){
         System.out.println("付钱");
     }  
 }

但我又不想向下面代码那样去主动学怎么找房子、怎么办理相关手续。

public void buy(){
     System.out.println("找房子");
     System.out.println("付钱");
     System.out.println("办理手续");
 }  

那这个时候我该怎么办呢?简单,有问题找中介,我只要会付钱,其他的东西中介帮我搞定。这个中介就是一个代理对象,在不改变“我”这个目标对象的功能的情况下,用代理对象的方式实现功能扩展。


 想要实现以上的需求有三种方式,也就是java的三种代理模式:静态代理、动态代理(JDK代理)、Cglib代理。

  1. 静态代理 (直接上代码)
    public interface IPeople{
         void buy();
     }
     /**
      *  目标对象实现了某一接口
      */
     public class People implements IPeople{
         public void buy(){
             System.out.println("付钱");
         }  
     }
    /**
      *  代理对象(中介)和目标对象(我)实现相同的接口
      */
     public class PeopleProxy implements IPeople{
         // 接收目标对象,以便调用sing方法
         private IPeople target;
        public PeopleProx(IPeople target){
            this.target = target;
        }
         // 对目标对象的buy方法进行功能扩展
         public void buy() {
             System.out.println("找房子");
             target.buy();
             System.out.println("办理手续");
         }
     }
     /**
      * 测试类
      */
     public class Test {
         public static void main(String[] args) {
             //目标对象
             IPeople target = new People();
             //代理对象
             IPeople proxy = new PeopleProxy(target);
             //执行的是代理的方法
             proxy.buy();
         }
     }

    总结:静态代理业务类只需要关注业务逻辑本身,保证了业务类的重用性。代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,需要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度

  2. 动态代理(JDK代理)
    public interface IPeople{
         void buy();
     }
    
    ​
     /**
      *  目标对象实现了某一接口
      */
     public class People implements IPeople {
         public void buy(){
             System.out.println("付钱");
         }  
     }
    /**
    JDK动态代理的实现原理大概流程
    1、为接口创建代理类的字节码文件
    2、使用ClassLoader将字节码文件加载到JVM
    3、创建代理类实例对象,执行对象的目标方法
    **/
    
    public class JdkProxyTest {
        public static void main(String[] args) {
            People target = new People();
            IPeople proxy = (IPeople) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                            System.out.println("找房子");
                            //执行目标对象方法
                            Object returnValue = method.invoke(target, objects);
                            System.out.println("办理手续");
                            return returnValue;
                        }
                    }
            );
            proxy.buy();
        }
    }

    总结:动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler invoke)。这样,在接口方法数量比较多的时候,可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使类职责更加单一,复用性更强。

  3. Cglib代理
     /**
      *  目标对象不用实现接口
      */
     public class People {
         public void buy(){
             System.out.println("付钱");
         }  
     }
    /**
     * Cglib子类代理工厂
     **/
    public class ProxyFactory implements MethodInterceptor {
    
        //维护目标对象
        private Object target;
    
        public ProxyFactory(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("找房子");
            Object returnValue = method.invoke(target,objects);
            System.out.println("办理手续");
            return returnValue;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            //目标对象
            People target= new People();
            //代理对象
            People targer =(People) new ProxyFactory(target).getProxyInstance();
            //执行代理对象的方法
            targer.buy();
    
        }
    }

    总结:静态代理和动态代理都需要目标对象实现接口,而Cglib代理则不需要这么麻烦。最后,顺便提下关于Cglib的问题,如果目标对象有不同方法,需要实现不同代理,那么代码需要怎么实现呢?

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看