头图

Table of contents

static proxy

Both the proxied class and the proxy class implement the Apple interface

 public interface Apple {
    Integer buyApple();
}

Create an instance of "Yantai" apple as the proxy class, which mainly implements a method of buying apples, which is also the method mainly used to be enhanced by the proxy later.

 public class YanTaiApple implements Apple{
    private Integer price;

    public YanTaiApple(Integer price) {
        this.price = price;
    }

    @Override
    public Integer buyApple(){
        return this.price;
    }
}

Create a proxy class for "Yantai" Apple, which mainly acts as a middleman, and the main enhancement is that the price is higher.

 public class YanTaiAppleProxy implements Apple{
    private Apple apple;

    public YanTaiAppleProxy(Apple apple) {
        this.apple = apple;
    }

    @Override
    public Integer buyApple() {
        Integer price = apple.buyApple()+2;
        System.out.println("苹果收购价格"+apple.buyApple()+"元,出售价"+price+"元");
        return price;
    }
}

In the following method, we go to buy apples through agents...

 public class StaticProxyTest {
    @Test
    public void test(){
        Apple apple = new YanTaiAppleProxy(new YanTaiApple(3));
        apple.buyApple();
    }
}
======结果======
苹果收购价格3元,出售价5元

Dynamic proxy

Carefully analyze the above static proxy, we will find that different proxy classes must be created for each class. If there are Henan apples, Xinjiang apples, Zhaotong apples.... Create a proxy class, can't we use one proxy to proxy multiple apples? Obviously static proxy is very limited.

Dynamic proxy is a proxy class that can dynamically create the original class through reflection, and then replace the original class with the proxy class in the system. In the java language, dynamic proxy is mainly implemented through the reflection mechanism.

JDK dynamic proxy

The jdk dynamic proxy is mainly implemented based on the interface and the Proxy class in the java reflection package, that is, the proxy class and the proxy class implement the same interface, and then dynamically expand through the Proxy proxy interface (emm.... Mainly see the following implementation ).

We continue to use the above Apple and YanTaiApple for both the interface and the original class, and then the proxy class is implemented as follows, we need to implement the interface InvocationHandler and then enhance the method call in the invoke method (the price of the agent increases by two yuan), when the original class associates this After the proxy class, the method of executing the interface will automatically enter the invoke method for enhancement.

 public class AppleProxyHandler implements InvocationHandler {
    private Apple apple;

    public AppleProxyHandler(Apple apple) {
        this.apple = apple;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取price字段
        Field field = apple.getClass().getDeclaredField("price");
        //放开权限 - 针对private
        field.setAccessible(true);
        Integer price = (Integer) field.get(apple);
        //重新设置值
        field.set(apple,price+2);
        return method.invoke(apple,args);
    }
}

Associate YanTaiApple and AppleProxyHandler instances through Proxy. Of course, the construction parameters of AppleProxyHandler can not only pass in the YanTaiApple instance, but also pass in the instance of other classes that implement the Apple interface, that is to say, AppleProxyHandler can proxy all the implementation classes of the Apple interface.

 public class JdkProxyTest {
    @Test
    public void test(){
        //关联
        Apple apple = (Apple) Proxy.newProxyInstance(this.getClass().getClassLoader(), 
                new Class[]{Apple.class}, 
                new AppleProxyHandler(new YanTaiApple(2)));
        System.out.println(apple.buyApple());
    }
}
=====结果=====
4

It is slightly unreasonable to carefully consider the above design, because the Apple interface may not only have the buyApple method but also other methods, so our proxy class clearly wants to be represented by the buyApple method, so the following optimization can be done.

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("buyApple".equals(method.getName())) {
        //获取price字段
        Field field = apple.getClass().getDeclaredField("price");
        //放开权限 - 针对private
        field.setAccessible(true);
        Integer price = (Integer) field.get(apple);
        //重新设置值
        field.set(apple, price + 2);
    }
    return method.invoke(apple,args);
}

cglib dynamic proxy

The main difference between cglib proxy and jdk proxy is that jdk dynamic proxy only supports interface proxy but not class proxy. The second parameter of Proxy.newProxyInstance can only be passed in the set of class objects of the interface. If a class is passed in, it will report java.lang.IllegalArgumentException: java.lang.Object is not an interface Exception. And cglib implements dynamic proxy through inheritance, and will dynamically generate a subclass object of the proxy class at runtime, so if this class is final modified, it cannot be proxy by cglib.

Let's continue to use Apple's example, but using cglib dynamic proxy, we don't need a unified interface class.

 public class YanTaiApple {
    public Integer price;

    public YanTaiApple(Integer price) {
        this.price = price;
    }

    public Integer buyApple(){
        return this.price;
    }
}

The proxy class implements the MethodInterceptor interface and then implements the proxy logic in the intercept method

 public class AppleProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object apple, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //apple是动态生成YanTaiApple的一个子类
        Field field = apple.getClass().getSuperclass().getDeclaredField("price");
        field.setAccessible(true);
        Integer price = (Integer) field.get(apple);
        field.set(apple,price+2);
        return methodProxy.invokeSuper(apple,objects);
    }
}

The test class needs to use the Enhancer class to set the proxy class to SuperClass and the proxy class to Callback

 public class CglibProxyTest {
    @Test
    public void test(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(YanTaiApple.class);
        enhancer.setCallback(new AppleProxy());
        //参数类型、参数值 - create相当于构造函数
        YanTaiApple yanTaiApple = (YanTaiApple) enhancer.create(new Class[]{Integer.class}, new Integer[]{3});
        System.out.println(yanTaiApple.buyApple());
    }
}
=====结果=====
5

eacape
205 声望8 粉丝

JAVA 攻城狮


« 上一篇
原型模式
下一篇 »
适配器模式