GOF23之代理模式(Proxy)

一、核心作用

间接对目标对象进行访问
可以详细控制某个对象的方法,对目标对象的实现功能上,增加额外的功能补充,扩展目标对象功能

二、常见应用场景

1、安全代理:屏蔽对真实角色的直接访问
2、远程代理:通过代理类处理远程方法的调用
3、延时加载:先加载轻量级,真正需要再加载真实对象

三、代理角色分类

  • 抽象角色:定义代理角色和真实角色的公共对外方法
  • 真实角色:实现抽象角色,定义真实角色要实现的业务逻辑,供代理角色调用
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑来实现抽象方法,并附加自己的操作
    在这里插入图片描述

四、代理模式分类:

1、静态代理
2、动态代理
3、Cglib代理

五、代码示例:

一、静态代理:

抽象角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname Star
* @Description 抽象角色
* @Date 2020/2/22 下午 06:41
* @Created by 朱进博 [email protected]
*/
public interface Star {
        void confer();

        void signContract();

        void bookTicket();

        void sing();

        void collectMoney();
}

真实角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname RealStar
* @Description TODO
* @Date 2020/2/22 下午 06:46
* @Created by 朱进博 [email protected]
*/
public class RealStar implements Star {
        @Override
        public void confer() {
                System.out.println("RealStar.confer");
        }

        @Override
        public void signContract() {
                System.out.println("RealStar.signContract");
        }

        @Override
        public void bookTicket() {
                System.out.println("RealStar.bookTicket");
        }

        @Override
        public void sing() {
                System.out.println("RealSta(周杰伦本人).sing");
        }

        @Override
        public void collectMoney() {
                System.out.println("RealStar.collectMoney");
        }
}
代理角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname ProxyStar
* @Description TODO
* @Date 2020/2/22 下午 06:48
* @Created by 朱进博 [email protected]
*/
public class ProxyStar implements Star{

        private Star star;

        public ProxyStar(Star star) {
                this.star = star;
        }

        @Override
        public void confer() {
                System.out.println("ProxyStar.confer");
        }

        @Override
        public void signContract() {
                System.out.println("ProxyStar.signContract");
        }

        @Override
        public void bookTicket() {
                System.out.println("ProxyStar.bookTicket");
        }

        @Override
        public void sing() {
                star.sing();
        }

        @Override
        public void collectMoney() {
                System.out.println("ProxyStar.collectMoney");
        }
}
测试:
package com.hezeu.proxy.staticProxy;

/**
* @Classname Client
* @Description 测试
* @Date 2020/2/22 下午 07:58
* @Created by 朱进博 [email protected]
*/
public class Client {
        public static void main(String[] args) {
                Star real = new RealStar();
                Star proxy = new ProxyStar(real);
                proxy.confer();
                proxy.signContract();
                proxy.bookTicket();
                proxy.sing();
                proxy.collectMoney();
        }
}

测试结果如下:

在这里插入图片描述

静态代理的优缺点:

优点:可以做到不修改目标对象功能的前提下对功能进行扩展或修改,符合开闭原则
缺点:因为代理对象需要与目标对象实现相同的接口,代理类爱多,同时一旦抽象角色增加方法,真实角色和代理角色都要维护,工作量大,不宜管理

二、动态代理:

使用JDK自带的动态代理
java.lang.reflect.Proxy 动态生成代理类和对象
java.lang.reflect.InvocationHandler(处理器接口)
可以通过invoke方法实现对真实角色的代理访问
每次通过proxy生成的代理类对象都要指定对应的处理器对象
package com.hezeu.proxy.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
* @Classname StarHandler
* @Description TODO
* @Date 2020/2/22 下午 08:16
* @Created by 朱进博 [email protected]
*/
public class StarHandler implements InvocationHandler {
        Star realStar;

        public StarHandler(Star realStar) {
                this.realStar = realStar;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object obj = null;
                System.out.println("真正的方法执行前!");
                System.out.println("面谈,签合同,预付款,订机票");

                if(method.getName().equals("sing")){
                        obj = method.invoke(realStar, args);
                }

                System.out.println("真正的方法执行后!");
                System.out.println("收尾款");
                return obj;
        }


动态代理相较于静态代理的优缺点:
对于静态代理而言,动态代理建好了开发的任务,减少了对业务接口的依赖,降低了耦合度

三、Cglib代理:

第三方代理技术,可以对目标对象接口实现代理,也可以进行继承代理,底层是动态的在内存中生成了目标对象的子类的字节码,并生成了相应的对象。
CGlib实现动态代理能满足没有接口的目标对象的代理对象实现。JDK动态代理与CGlib动态代理是实现Spring AOP的基础

代码示例:
真实角色(没有实现接口)
package com.hezeu.proxy.CGlib;

/**
* @Classname RealStar
* @Description TODO
* @Date 2020/2/22 下午 06:46
* @Created by 朱进博 [email protected]
*/
public class RealStar {

        public void confer() {
                System.out.println("RealStar.confer");
        }

        public void signContract() {
                System.out.println("RealStar.signContract");
        }

        public void bookTicket() {
                System.out.println("RealStar.bookTicket");
        }

        public void collectMoney() {
                System.out.println("RealStar.collectMoney");
        }

        public void sing() {
                System.out.println("RealStar(CGlib周杰伦).sing");
        }
}
cglib代理类,需要实现MethodInterceptor
package com.hezeu.proxy.CGlib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
/**
* @Classname ProxyStar
* @Description TODO
* @Date 2020/2/22 下午 10:09
* @Created by 朱进博 [email protected]
*/
public class ProxyStar implements MethodInterceptor {
        private Object target;

        public Object getInstance(Object target){
                this.target=target;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(this.target.getClass());
                enhancer.setCallback(this);
                return enhancer.create();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("事物开始");
                Object result = methodProxy.invokeSuper(o,objects);
                System.out.println("事物结束");
                return result;
        }
}
测试类:
package com.hezeu.proxy.CGlib;

/**
* @Classname Client
* @Description TODO
* @Date 2020/2/22 下午 08:20
* @Created by 朱进博 [email protected]
*/
public class Client {
        public static void main(String[] args) {
                ProxyStar proxy = new ProxyStar();
                RealStar realStar = (RealStar) proxy.getInstance(new RealStar());
                realStar.sing();


        }
}

动态代理和CGlib代理总结

使用JDK动态代理需要实现一个或多个接口,若想代理没有实现接口的类,需要使用Cglib
使用Cglib 需要导入
cglib-xxx.jar
asm-xxx.jar

在Spring的AOP编程中
如果加入容器的目标对象有实现接口用JDK代理
如果目标对象没有实现接口,用Cglib代理

水平有限,如有错漏,还请不吝赐教

发布了6 篇原创文章 · 获赞 1 · 访问量 1129

猜你喜欢

转载自blog.csdn.net/weixin_44789225/article/details/104452319