zoukankan      html  css  js  c++  java
  • 动态代理(设计模式)

    代理模式概述

         代理模式属于结构型模式,指的是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    代理模式包含角色及其职责:

    • 抽象角色[Subject]:通过接口或抽象类声明真实角色待实现方法;
    • 代理角色[Proxy]:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作(可做增强操作);
    • 真实角色[RealSubject]:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用;
    • 代理模式有不同的形式,主要有两种,静态代理、动态代理(静态代理较简单不做介绍)
    • 动态代理分为两种:
      • jdk 动态代理,基于接口;
      • cglib 代理,基于类; 可以在内存中动态的创建对象,而不需要实现接口。

    代理模式包含角色及其职责:

    设计原则:

    • 隔离原则

        在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到桥梁的作用, 其特征是代理类与委托类有同样的接口。

    • 开闭原则

         代理类不仅仅是一个隔离客户端和委托类的中介。我们还可以借助代理来在增加一些功能,而不需要修改原有代码,严重的符合开闭原则。

    代理模式的优点:

    • 公共业务交给代理角色,实现业务的分工。公共业务发生扩展的时无需修改源码,符合开闭原则,系统具有较好的灵活性和可扩展性;
    • 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;

    源码演示:

    第一个:jdk动态代理

    1、定义接口类

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:08
     */
    public interface IUserDao {
    
        void findUserPojo();
    }

    2、实现接口类

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:08
     */
    public class UserImpl implements IUserDao {
    
        @Override
        public void findUserPojo() {
            System.out.println("此方法为jdk动态代理。查询用户信息为:{userID:1001,userName:Northeast Tycoon,alias:Java.Zhao}");
    
        }
    }

    3、jdk动态代理实现类

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:07
     */
    public class ProxyInvocationHandler implements InvocationHandler {
    
        // 需要代理的对象,既:真实对象
        private Object target;
    
        public void setObject(Object target) {
            this.target = target;
        }
    
    
        public Object getProxy() {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        /*
         * 处理代理对象的方法时会调用此方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            // 通过反射实现动态代理,调用真实对象方法
            Object result = method.invoke(target, args);
            after();
            return result;
        }
    
        //  执行前-增强方法
        public void before() {
            System.out.println(" This is northeasttycoon jdkDynamicProxy,调用动态代理方法前------");
        }
        //  执行后-增强方法
        public void after() {
            System.out.println("This is northeasttycoon jdkDynamicProxy,调用动态代理方法后------"); } }

    第二个:cglib 动态代理

    1、定义目标对象(真实对象)

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:10
     */
    public class UserDao {
    
        public void findUserPojo() {
            System.out.println("此方法为CGlib动态代理。查询用户信息为:{userID:1001,userName:Northeast Tycoon,alias:Java.Zhao}");
    
        }
    }

    2、cglib 动态代理类

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:28
     */
    public class CglibDynamicProxy implements MethodInterceptor {
    
        //维护一个目标对象
        private Object target;
    
        //构造器,传入一个被代理的对象
        public CglibDynamicProxy(Object target) {
            this.target = target;
        }
    
        //返回一个代理对象:  是 target 对象的代理对象
        public Object getProxyInstance() {
            //1. 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            //2. 设置enhancer对象的父类
            enhancer.setSuperclass(target.getClass());
            //3. 设置enhancer的回调对象
            enhancer.setCallback(this);
            //4. 创建子类对象,即代理对象
            return enhancer.create();
    
        }
    
        /**
         * 重写  intercept 方法,会调用目标对象的方法
         * @param arg0 cglib生成的代理对象
         * @param method 被代理对象的方法
         * @param args     传入方法的参数
         * @param arg3 代理的方法
         * @return 对象
         * @throws Throwable
         */
        @Override
        public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
            System.out.println("cglib代理模式 ~~ start");
            Object returnVal = method.invoke(target, args);
            System.out.println("cglib代理模式 ~~ end");
            return returnVal;
        }
    
    }

    测试类

    package com.northeasttycoon.proxy.dynamic.proxy;
    
    import org.junit.jupiter.api.Test;
    
    /**
     * @author :tycoon
     * @date :2018-10-01 9:18
     */
    public class TestProxy {
    
        /**
         * jdk 动态代理实现
         */
        @Test
        public void test01(){
            //需要被代理的对象
            UserImpl userService = new UserImpl();
    
            //生成代理类
            ProxyInvocationHandler pih = new ProxyInvocationHandler();
            pih.setObject(userService);
            IUserDao proxy = (IUserDao) pih.getProxy();
    
            //调用代理类的方法
            proxy.findUserPojo();
        }
    
        /**
         * cglib的动态代理
         */
        @Test
        public void test02(){
    
            //创建目标对象
            UserDao target = new UserDao();
            //获取到代理对象,并且将目标对象传递给代理对象
            UserDao proxyInstance = (UserDao)new CglibDynamicProxy(target).getProxyInstance();
    
            //执行代理对象的方法,触发intecept 方法,实现对目标对象的调用
            proxyInstance.findUserPojo();
        }
    }

    测试结果:

  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/northeastTycoon/p/15365960.html
Copyright © 2011-2022 走看看