设计模式-代理模式

目录

一.什么是代理模式

二.代理模式的作用

三.静态代理

四.Jdk动态代理

五.Cglib动态代理

六.JDK动态代理与CGLIB动态代理的区别


一.什么是代理模式

        代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客服端和目标对象之间起到中介作用。
属于结构型设计模式。

二.代理模式的作用

设想这样的一个场景:我们想请杰伦演出,但是杰伦只唱歌别的琐碎的业务不想做,这时候还怎么办?这时候当然是需要找一个代理,来帮杰伦谈薪资,安排行程,买火车票。这就相相当与我们的代理模式。

三.静态代理

        直接定义代理类,实现目标对象的接口,实现他的方法并对其增强

这种方式不宜与扩展。

先创建目标对象的接口 与实现类:

ISingServer:

public interface ISingService {
    String sing(String str);
}

JaySingServer实现类:

public class JaySingService implements ISingService {
    @Override
    public String sing(String str) {
        if ("花海".equals(str) ) {
            System.out.println("不要你离开~距离隔不开~");
            return str;
        } else if ("明明就".equals(str)) {
            System.out.println("明明就他比较温柔~~~");
            return str;
        }
        return "不会唱~~~~";
    }
}

VaeSingServer实现类:

public class VaeSingService implements ISingService {
    @Override
    public String sing(String str) {
        if ("有何不可".equals(str) ) {
            System.out.println("为你唱这首歌~他没什么风格~仅仅代表着我想给你快乐~");
            return str;
        }
        return "不会唱~~~~";
    }
}

静态代理:

public class StaticProxy implements ISingService {
    //静态代理需要继承目标对象  然后重写方法并对其增强
    //目标对象
    private ISingService target;

    //创建构造器
    public StaticProxy(ISingService target) {
        this.target = target;
    }

    @Override
    public String sing(String str) {
        //执行目标方法前需要做的事
        before();

        String result = target.sing(str);
        //执行目标方法后需要做的事
        after();
        return result + "--好听!好听!";
    }

    public void before() {
        System.out.println("演出前需要与经纪人先谈好演出费");
    }
    public void after() {
        System.out.println("唱完了,经纪人需要安排回去的返程");
    }
}

test:

public static void main( String[] args )
    {
        ISingService jaySing = new JaySingService();
        //静态代理
        StaticProxy proxy = new StaticProxy(jaySing);
        System.out.println(proxy.sing("花海"));
    }
}

四.Jdk动态代理

        静态代理的灵活性不高,所以我们引入了动态代理的方式

        如果目标对象实现的有接口,那么我们就可以使用JDK代理模式。JDK动态代理相当与实现目标对象的接口,然后重写他的方法并对其进行增强。

public class JdkProxy implements InvocationHandler {
    //要被代理的对象
    private ISingService target;

    public JdkProxy(ISingService target) {
        this.target = target;
    }

    public ISingService creatTarget() {
        /*
         *Proxy.newProxyInstance
         *第一个参数:目标的对象加载器
         * 第二个参数:目标对象的接口
         * 第三个参数是InvocationHandler类 这个类的invoke方法是做增强的地方
         */
        ISingService proxyTarget = (ISingService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
        return proxyTarget;
    }

    /**
     * Jdk动态代理要实现这个方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public  Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行目标方法前需要做的事
        before();
        //执行目标对象的方法
        String result = (String) method.invoke(target,args);
        //执行目标方法后需要做的事
        after();
        return result + "--好听!好听!";
    }


    public void before() {
        System.out.println("演出前需要与经纪人先谈好演出费");
    }
    public void after() {
        System.out.println("唱完了,经纪人需要安排回去的返程");
    }
}

test:

public class App 
{
    public static void main( String[] args )
    {
        //Jdk动态代理
        ISingService vaeSing = new VaeSingService();
        ISingService proxy = new JdkProxy(vaeSing).creatTarget();
        System.out.println(proxy.sing("有何不可"));
    }
}

五.Cglib动态代理

        但是当目标对象没有实现任何接口的时候我们就没法使用JDK动态代理的方式。那么这个时候我们只能使用CGLIB代理。CGLIB的本质其实是代理类继承了目标对象,并覆盖相关方法。

创建CGLIB代理类实现MethodInterceptor 接口 并重写他的intercept接口:

public class CglibProxy implements MethodInterceptor {

    private ISingService target;

    public CglibProxy(ISingService target) {
        this.target = target;
    }

    public ISingService creatTaget() {
        Enhancer enhancer = new Enhancer();
        //指定父类class
        enhancer.setSuperclass(target.getClass());
        //指定回调方法
        enhancer.setCallback(this);
        //创建代理对象
        return (ISingService) enhancer.create();
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //执行目标方法前需要做的事
        before();
        //执行目标对象的方法
        String result = (String) method.invoke(target,objects);
        //String result = (String) methodProxy.invokeSuper(o,objects); //这种方式一样
        //执行目标方法后需要做的事
        after();
        return result + "--好听!好听!";
    }


    public void before() {
        System.out.println("演出前需要与经纪人先谈好演出费");
    }
    public void after() {
        System.out.println("唱完了,经纪人需要安排回去的返程");
    }
}

test:

public class App 
{
    public static void main( String[] args )
    {
        ISingService jaySing = new JaySingService();
        //静态代理
//        StaticProxy proxy = new StaticProxy(jaySing);
//        System.out.println(proxy.sing("花海"));

        //Jdk动态代理
//        ISingService vaeSing = new VaeSingService();
//        ISingService proxy = new JdkProxy(vaeSing).creatTarget();
//        System.out.println(proxy.sing("有何不可"));

        //Cglib动态代理
        ISingService proxy = new CglibProxy(jaySing).creatTaget();
        System.out.println(proxy.sing("明明就"));

    }

}

六.JDK动态代理与CGLIB动态代理的区别

  1. 生成代理类,CGLIB要用到asm框架,要比IDK慢,调用cglib要快,因为是fastclass机制,但是可以忽略,这也是为什么源码一般用jdk
  2. jdk代理是通过接口,所以代理类必须要实现接口,或者可以直接代理空接口;cglib代理是通过继承的方式去实现,所以不能被继承的类或者方法是不能代理的
  3. JDK跟CGLIB都不能代理非public方法(spring事务失效)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w7486

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值