代理模式

代理模式

为其他对象提供一种代理,以控制对这个对象的访问。

使用场景

  1. 保护目标对象
  2. 增强目标对象

静态代理

显式声明被代理对象

使用场景

代理类,只代理 一个被代理类

  • 定义一个person接口
public interface Person {
    void findLove();
}
  • 被代理类
public class Son implements Person {
    @Override
    public void findLove() {
        System.out.println("肤白 貌美 大长腿");
    }
}
  • 代理类
public class Father implements Person {
    private Person person;

    public Father(Son son) {
        this.person = son;
    }

    @Override
    public void findLove() {
        before();
        person.findLove();
        after();
    }

    private void before() {
        System.out.println("开始物色");
    }

    private void after() {
        System.out.println("寻找完毕");
    }
}
  • 测试类
public class StaticProxyTest {
    public static void main(String[] args) {
        Father father = new Father(new Son());
        father.findLove();
    }
}

动态代理

动态配置和替换被代理对象。动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,可以代理很多类。

JDK代理

JDK动态代理,需要被代理类实现一个接口

  • 代理类
public class JDKMeipo implements InvocationHandler {
    private Object target;

    public Object getInstance(Object target) {
        this.target = target;

        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        Object object = method.invoke(this.target, args);
        after();

        return object;
    }

    private void before() {
        System.out.println("开始物色");
    }

    private void after() {
        System.out.println("寻找完毕");
    }
}
  • 被代理类
public class Girl implements Person {
    @Override
    public void findLove() {
        System.out.println("高富帅");
    }
}
  • 测试类
public class JDKProxyTest {
    public static void main(String[] args) {
        Object o = new JDKMeipo().getInstance(new Girl());
        Person instance = (Person) o;
        instance.findLove();

        // 输出代理对象,通过jad反编译 查看代理类内部情况
//        try {
//            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
//            FileOutputStream os = new FileOutputStream("F://$Proxy0.class");
//            os.write(bytes);
//            os.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

    }
}
  • 反编译出来的代理类

通过反编译可以看出来,生成的代理对象中实现了 被代理类所实现的接口,从而实现方法的增强

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 

import com.hh.proxy.Person;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy
    implements Person
{

    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void findLove()
    {
        try
        {
            super.h.invoke(this, m3, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    static 
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m3 = Class.forName("com.hh.proxy.Person").getMethod("findLove", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        }
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

CGLib代理

被代理类不用实现接口。

  • 被代理类
public class Boy {

    public void findLove() {
        System.out.println("白富美");
    }
}
  • 代理类
public class CglibMeipo implements MethodInterceptor {

    public Object getInstance(Class<?> clazz) {
        //相当于Proxy,代理的工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        before();
        Object obj = methodProxy.invokeSuper(o, objects);
        after();

        return obj;
    }

    private void before() {
        System.out.println("开始物色");
    }

    private void after() {
        System.out.println("寻找完毕");
    }
}

  • 测试类
public class CglibProxyTest {
    public static void main(String[] args) {

        Boy boy = (Boy) new CglibMeipo().getInstance(Boy.class);
        boy.findLove();

    }
}

CGLib代理与JDK代理对比

  1. JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理对象。
  2. JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
  3. JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高

静态代理和动态的本质区别

  1. 静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步 新增,违背开闭原则
  2. 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开 闭原则。
  3. 若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成, 无需修改代理类的代码

代理模式的优缺点

优点

  1. 代理模式能将代理对象与真实被调用的目标对象分离
  2. 一定程度上降低了系统的耦合度,扩展性好
  3. 可以起到保护目标对象的作用
  4. 可以对目标对象的功能增强

缺点

  1. 代理模式会造成系统设计中类的数量增加
  2. 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
  3. 增加了系统的复杂度
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值