美文网首页
设计模式 代理模式(静态代理、JDK动态代理以及CGLIB动态代

设计模式 代理模式(静态代理、JDK动态代理以及CGLIB动态代

作者: dylan丶QAQ | 来源:发表于2020-11-19 15:00 被阅读0次

    起因:在看架构设计的时候,看到代理模式,回想起来,做了这么几年的java,虽然知道代理模式,但是未曾深入了解过,所以去打算研究一下代理模式。


    1 代理模式

    代理模式的定义:
    由于某些原因需要给某对象提供一个代理以控制对该对象的访问。
    这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

    2 代理模式 概述

    代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用。
    对于java的代理模式,一般可分为:静态代理、动态代理、以及CGLIB实现动态代理。

    代理模式的主要优点有:

    • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
    • 代理对象可以扩展目标对象的功能;
    • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

    其主要缺点是:

    • 代理模式会造成系统设计中类的数量增加
    • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
    • 增加了系统的复杂度;

    以上缺点可以使用动态代理来解决


    3 代理模式 模式结构

    代理模式的主要角色如下:

    • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
    • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
    • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
    4 静态代理 代码实现
    package com.test.proxy;
    
    public interface Target {
    
        public String execute();
    }
    
    
    package com.test.proxy;
    
    public class TargetImpl implements Target {
    
        @Override
        public String execute() {
            System.out.println("TargetImpl execute!");
            return "execute";
        }
    }
    
    package com.test.proxy;
    
    public class Proxy implements Target{
    
        private Target target;
    
        public Proxy(Target target) {
            this.target = target;
        }
    
        @Override
        public String execute() {
            System.out.println("perProcess");
            String result = this.target.execute();
            System.out.println("postProcess");
            return result;
        }
    }
    
    
    
    package com.test.proxy;
    
    public class ProxyTest {
        public static void main(String[] args) {
    
            Target target = new TargetImpl();
            Proxy p = new Proxy(target);
            String result =  p.execute();
            System.out.println(result);
        }
    
    }
    

    总结:由我们创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。

    5 动态代理 代码实现
    package com.agency.staticproxy;
    
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class App {
        public static void main(String[] args) {
            // 目标对象
    //        IUserDao target = new UserDao();
            MemberServiceImpl target = new MemberServiceImpl();
            // 【原始的类型 class cn.itcast.b_dynamic.UserDao】
            System.out.println(target.getClass());
    
            // 给目标对象,创建代理对象
            MemberService memberService = (MemberService) new ProxyFactory(target).getProxyInstance();
    
            // class $Proxy0   内存中动态生成的代理对象
            System.out.println(memberService.getClass());
    
            // 执行方法   【代理对象】
            memberService.getUserById();
        }
    }
    
    class ProxyFactory{
    
        //维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target){
            this.target=target;
        }
    
        //给目标对象生成代理对象
        public Object getProxyInstance(){
    
            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("12222");
                            //执行目标对象方法
                            Object returnValue = method.invoke(target, args);
                            String name = method.getName();
                            System.out.println("233333");
                            return returnValue;
                        }
                    }
            );
    
        }
    
    }
    
    class MemberServiceImpl implements MemberService {
    
        @Override
        public void getUserById() {
            System.out.println(123);
        }
    }
    
    interface MemberService {
        void getUserById();
    }
    
    

    总结:在程序运行时,运用反射机制动态创建而成。

    0.根据所传入的参数生成一个代理类
    1.代理类实现了相关接口,继承了Proxy,其构造函数是有参构造,传入一个InvocationHandler。
    2.所以,其使用代理类,调用方法,都会先调用InvocationHandler中的invoke方法,
    3.至于要不要调用代理类的方法,需要看,在invoke中是否调用了method.invoke(target, args)。

    6 CGLIB代理 代码实现
    package com.agency.cglib;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class CglibTest {
    
        public static void main(String[] args) {
            System.out.println("***************");
            Target target = new Target();
            CglibTest test = new CglibTest();
            Target proxyTarget = (Target) test.createProxy(Target.class);
            String res = proxyTarget.execute();
            System.out.println(res);
        }
    
        public Object createProxy(Class targetClass) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(targetClass);
            enhancer.setCallback(new MyMethodInterceptor());
            return enhancer.create();
        }
    
    }
    
    class MyMethodInterceptor implements MethodInterceptor {
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println(">>>>MethodInterceptor start...");
            Object result = proxy.invokeSuper(obj,args);
            System.out.println(">>>>MethodInterceptor ending...");
            return "result";
        }
    }
    
    class Target {
    
        public String execute() {
            String message = "-----------test------------";
            System.out.println(message);
            return message;
        }
    }
    

    总结:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,
    并在子类中采用方法拦截的技术拦截所有父类方法的调用,
    顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。


    不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!

    相关文章

      网友评论

          本文标题:设计模式 代理模式(静态代理、JDK动态代理以及CGLIB动态代

          本文链接:https://www.haomeiwen.com/subject/bbxliktx.html