• 动态代理(设计模式)


    代理模式概述

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

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

    • 抽象角色[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();
        }
    }

    测试结果:

  • 相关阅读:
    SharePoint Framework 构建你的第一个web部件(二)
    win32
    win32
    win32
    win32
    C++ 将filesystem::path转换为const BYTE*
    win32
    win32
    win32
    win32
  • 原文地址:https://www.cnblogs.com/northeastTycoon/p/15365960.html
Copyright © 2020-2023  润新知