Java设计模式之代理

代理模式从业务上讲其实还是比较好理解的,比如过年我想买一张火车票,总也买不到,怎么办?

比如可以让男朋友去火车站排队去买!这叫静态代理

一、静态代理

首先我们定义一个接口,买火车票

public interface BuyTicket {
    public void buy();
}

然有个美女,想要回家,需要买一张火车票

public class BuyTicketGirl implements BuyTicket {
    @Override
    public void buy() {
        System.out.println("I need a ticket");
    }
}

很遗憾,过年的时候火车票不好买,美女只好求男朋友去帮忙买

public class BuyTicketBoy implements BuyTicket {

    private BuyTicket buyTicket;

    public BuyTicketBoy(BuyTicket buyTicket) {
        this.buyTicket = buyTicket;
    }

    @Override
    public void buy() {
        System.out.println("I am boy friend");
        buyTicket.buy();
    }
}
public class Main {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicketGirl();
        BuyTicket proxy = new BuyTicketBoy(buyTicket);
        proxy.buy();
}
}

买到了,输出:

I am boy friend
I need a ticket

很好,但这有一个问题,如果让男朋友帮忙买票,前提是每个人都有男朋友,显然这并不现实。

这也是静态代理的缺点:代理只能为一个类服务,如果需要为很多类服务,需要写很多代理类,这并不是我们想看到的。

那怎么办?

如果你去过火车站,会发现火车站就会有一些到处晃悠的大哥悄没声问:买票不?

对于买票这个行为来说,他的身份就是代理,他能帮我完成买票这个行为,具体他是谁,怎么做到,我不关心。

而且在买票这个事上,他能帮很多人实现梦想。这就是动态代理。

二、动态代理

首先我们先实现一个买票大哥,他持有一个object属性,意味他可以为所有人帮忙买票,如果你需要,说不定还可以帮忙买房买车。

public class ProxyHandler implements InvocationHandler {

    private Object object;

    public ProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("I am Dynamic Proxy");
        method.invoke(object,args);
        return null;
    }
}

开始买票

public class Main {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicketGirl();

        ProxyHandler proxyHandler = new ProxyHandler(buyTicket);
        BuyTicket proxyInstance = (BuyTicket) Proxy.newProxyInstance(
                buyTicket.getClass().getClassLoader(),
                buyTicket.getClass().getInterfaces(),
                proxyHandler);

        proxyInstance.buy();
}
}

输出:

I am Dynamic Proxy
I need a ticket

也买到票了,这就是动态代理

三、动态代理底层原理

实际上JDK动态代理是采用字节重组,重新生成对象来代替原始对象以达到动态代理的目的。JDK Proxy生成对象的步骤如下。

1.拿到被代理对象的引用BuyTicket 并且获取到它所有的接口反射获取。(这也是为什么JDK动态代理需要代理类和被代理类都要事先同一接口的原因)

2.JDK Proxy类重新生成一个新的类,这个新的类需要实现被代理类(BuyTicket)的所有实现的所有接口(buy)

3.动态生成java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)

4.编译新生成的java代码.class

5.再重新加载到JVM中运行


四、Spring AOP中的代理机制

springboot没有默认使用的代理 : (SpringBoot中默认开启了proxyTargetClass,默认都是使用CGLIB代理)
  • 如果代理的是实现接口的类,则使用JDK动态代理. 只要代理的类实现了至少一个接口,那么目标类型实现的接口都将会使用JDK动态代理
  • 如果代理的是子类,没有实现任何接口,则使用CGLIB代理


参考:

https://www.jianshu.com/p/8aee43cbc373

https://www.jianshu.com/p/ab6b0c9d549c

https://www.jianshu.com/p/9bcac608c714

原文地址:https://www.cnblogs.com/wangbin2188/p/15250112.html