• jdk动态代理----实战例子


    代理模式基本介绍

    1. 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理
      对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的 功能操作,即扩展目标对象的功能。
    2. 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
    3. 代理模式有不同的形式, 主要有三种 静态代理动态代理 (也叫JDK代理或接口代 理)和 Cglib代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于 动态代理的范畴)

    1、静态代理

    1.1 优缺点
    1. 优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
    2. 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
    3. 一旦接口增加方法,目标对象与代理对象都要维护
    1.2 类图

    在这里插入图片描述

    1.3 代码演示

    接口

    public interface ITeacherDao {
        void teach();
    }
    
    • 1
    • 2
    • 3

    实现类

    public class TeacherDao implements ITeacherDao{
        @Override
        public void teach() {
            System.out.println("老师上课中………………");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代理类

    public class TeacherDaoProxy implements ITeacherDao{
        /**
         * 目标对象,通过接口来聚合
         */
        private ITeacherDao target;
        public TeacherDaoProxy(ITeacherDao target) {
            this.target = target;
        }
        @Override
        public void teach() {
            System.out.println("代课老师上课中…………");
            target.teach();
            System.out.println("代课老师上课结束………………");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类

    public class Client {
    
        public static void main(String[] args) {
            TeacherDao teacherDao =new TeacherDao();
            TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
            teacherDaoProxy.teach();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2. 动态代理之jdk动态代理

    基本概念:
    AOP:面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得
    业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
    通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

    AOP 底层使用动态代理
    (1)有两种情况动态代理
    第一种 有接口情况,使用 JDK 动态代理
    ⚫ 创建接口实现类代理对象,增强类的方法
    第二种 没有接口情况,使用 CGLIB 动态代理
    ⚫ 创建子类的代理对象,增强类的方法

    2.1 jdk动态代理----对feign对象的代理

    static Object
    newProxyInstance(ClassLoader loader, 类[] interfaces, InvocationHandler h)
    返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序

    第一参数,类加载器
    第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
    第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

    2.2 类图

    在这里插入图片描述

    2.3 代码实现

    接口

    public interface ITeacherDao {
        void teach();
        void sayHello(String name);
    }
    
    • 1
    • 2
    • 3
    • 4

    接口实现

    public class TeacherDao implements ITeacherDao{
        @Override
        public void teach() {
            System.out.println("老师正在上授课中………………");
        }
        @Override
        public void sayHello(String name) {
            System.out.println(name+"我爱你");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    代理类

    public class ProxyFactory {
        //维护一个目标对象
        private Object target;
        //构造,初始化目标对象
        public ProxyFactory(Object target) {
            this.target = target;
        }
        //给目标对象生成一个代理对象
        public Object getProxyInstance(){
            /*
             * newProxyInstance(ClassLoader loader,
                                              Class[] interfaces,
                                              InvocationHandler h)
              1、ClassLoader loader 指定当前目标对象使用的类加载器,获取加载器的方法固定
              2、Class[] interfaces 目标对象实现接口类型,使用泛型方法确认类型
              3、InvocationHandler 事情处理,执行目标对象方法时,会触发事情处理方法,会把当前执行的目标对象方法作为参数传入
             */
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("jdk动态代理开始……");
                            Object invoke = method.invoke(target, args);
                            return invoke;
                        }
                    });
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    测试

    public class Client {
        public static void main(String[] args) {
            //目标对象
            ITeacherDao target = new TeacherDao();
            //给目标对象创建代理对象
            ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
            proxyInstance.teach();
            proxyInstance.sayHello("老王");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2.4 下面看我们springcloud中的feign调用时如何使用代理对象来完成异常空指针等的处理

    public class FeignProxyInvocationHandler implements InvocationHandler {
        /**
         * feign接口
         */
        private Object feignClient;
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke = method.invoke(feignClient, args);
            //RespResult是我们的通用返回类型
            if (invoke instanceof RespResult) {
                RespResult result = (RespResult) invoke;
                //这里是判断是否返回成功,并且结果不是null
                AssertUtil.assertTrue(CommonUtils.isRespSuccess(result) && result.getData() != null, result.getCode(), result.getMessage());
                return result;
            }
            return invoke;
        }
        /**
         * 实例化代理对象
         * 这里的this指上面的invoke方法
         * @param delegate
         * @return
         */
        public Object buildProxy(Object delegate) {
            this.feignClient = delegate;
            return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
        }
        public static Object getProxy(Object feignClient) {
            return new FeignProxyInvocationHandler().buildProxy(feignClient);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在其他地方使用:
    比如某实现类

    public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper,UserInfo> implements UserInfoService,InitializingBean{
    	@Resource
    	private SmsFeignClient smsFeignClient;
    	//………………业务代码………………
      @override 
      public void afterPropertiesSet() throws Exception{
     	smsFeignClient = (SmsFeignClient)FeignProxyInvocationHandler.getProxy(smsFeignClient);
     	}
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    好处:方法调用处不必考虑空指针、调用失败等(如果其它异常也可以自己在代理类的invoke方法中自己统一加)

    3. 动态代理之CGLIB 动态代理

    1. 静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只
      是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现 代理-这就是Cglib代理
    2. Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功 能扩展, 有些书也将Cglib代理归属到动态代理。
    3. Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接 口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截
    4. 在AOP编程中如何选择代理模式:
    1. 目标对象需要实现接口,用JDK代理
    2. 目标对象不需要实现接口,用Cglib代理 5) Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类
    3.1 类图

    在这里插入图片描述

    3.2 代理演示

    被代理类

    public class TeacherDao {
        public void teach(){
            System.out.println("老师授课中…………");
        }
        public String teach2(){
          return "老师授课中…………";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代理类

    public class ProxyFactory implements MethodInterceptor {
        //维护一个目标对象
        private Object target;
        //构造器
        public ProxyFactory(Object target) {
            this.target = target;
        }
        //返回一个代理对象,是target的代理对象
        public Object getProxyInstance(){
            //1.创建工具类
            Enhancer enhancer = new Enhancer();
            //2.设置父类
            enhancer.setSuperclass(target.getClass());
            //3.设置回调函数
            enhancer.setCallback(this);
            //4.创建子类,即代理对象
            return enhancer.create();
        }
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("cglib代理模式开始…………");
            Object invoke = method.invoke(target, args);
            System.out.println("cglib代理模式结束…………");
            return invoke;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    测试类

    public class Client {
    
        public static void main(String[] args) {
            //目标对象
            TeacherDao teacherDao = new TeacherDao();
            //将目标对象传递给代理对象
            ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
            TeacherDao proxyInstance = (TeacherDao)proxyFactory.getProxyInstance();
            proxyInstance.teach();
    
            String s = proxyInstance.teach2();
            System.out.println(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    大数据开发之数据仓库
    Django搭建和数据迁移
    光谱图像超分辨率综述
    C/C++结构体使用总结
    中国与外国互免签证协定一览表(更新至2022年7月8日)
    maven 阿里源配置完整 亲测有效
    WeakMap 弱引用 不会被GC所考量
    3.2 C++高级编程_抽象类界面
    面试经典150题——矩阵置零
    刚刚阿里面软件测试回来,3+1面任职阿里P7,年薪28*15薪
  • 原文地址:https://blog.csdn.net/m0_37635053/article/details/126456116