设计模式之代理模式

代理模式是比较重要的设计模式之一,在面向对象的系统中,有些对象由于某些原因(比如创建对象的开销很大,或者某些操作需要安全校验机制,或者其他的额外控制),典型应用就是AOP。

主要分为静态代理和动态代理,静态代理就是通过java代码写死代理类,动态代理就是动态的生成代理类,主要分为jdk动态代理和cglib动态代理,区别是jdk动态代理需要被代理的对象必须有父类,运行时动态的生成父类的子类,也就是代理类和被代理类是同一个父类,跟静态代理差不多,cglib动态代理则没有这个限制,运行的时候动态生成被代理类的子类。

1、静态代理

①定义父类

public interface Image {
    void display();
}

②被代理类

public class RealImage implements Image {

    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk(fileName);
    }

    @Override
    public void display() {
        System.out.println("Display: " + fileName);
    }

    private void loadFromDisk(String fileName) {
        System.out.println("Loading: " + fileName);
    }
}

③代理类

public class ProxyImage implements Image {

    private RealImage realImage;
    private String fileName;

    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void display() {
        if (Objects.isNull(realImage)) {
            realImage = new RealImage(fileName);
        }
        realImage.display();

    }
}

④测试

public class _Test {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        image.display();
    }
}

代理类本身持有被代理类的对象,从而实现代理

2、jdk动态代理

①定义父类

public interface Subject {
    Integer sellBooks();

    String speak();
}

②被代理类

public class RealSubject implements Subject {
    @Override
    public Integer sellBooks() {
        System.out.println("卖书");
        return 1;
    }

    @Override
    public String speak() {
        System.out.println("说话");
        return "张三";
    }
}

③代理类书写(需要实现InvocationHandler接口)

public class MyInvocationHandler implements InvocationHandler {


    private Subject realSubject;

    public MyInvocationHandler(Subject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用代理类");
        if ("sellBooks".equals(method.getName())) {
            int invoke = (int) method.invoke(realSubject, args);
            System.out.println("调用卖书方法");
            return invoke;
        } else {
            String invoke = (String) method.invoke(realSubject, args);
            System.out.println("调用说话方法");
            return invoke;
        }
    }
}

④测试

public class _Test {
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        MyInvocationHandler invocationHandler = new MyInvocationHandler(realSubject);
        Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, invocationHandler);
        proxyClass.sellBooks();
        proxyClass.speak();

    }
}

动态的生成代理对象(继承自Proxy,实现Subject接口)

3、cnlib动态代理

①被代理类

public class Engineer {
    /**
     * 可以被代理
     */
    public void eat() {
        System.out.println("工程师正在吃饭");
    }

    /**
     * final 方法不会被生成的字类覆盖
     */
    public final void work() {
        System.out.println("工程师正在工作");
    }

    /**
     * private 方法不会被生成的字类覆盖
     */
    private void play() {
        System.out.println("this engineer is playing game");
    }
}

②cglib代理类编写

public class CglibProxy implements MethodInterceptor {

    private Object target;

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

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("### before invocation");
        Object invoke = method.invoke(target, objects);
        System.out.println("### after invocation");
        return invoke;
    }

    public static Object getProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new CglibProxy(target));
        return enhancer.create();
    }

}

③测试

public class _Test {

    public static void main(String[] args) {
        Engineer engineer = (Engineer) CglibProxy.getProxy(new Engineer());

        engineer.eat();
    }
}

使用cglib需要引入相关依赖包

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.10</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>3.2.10</version>
        </dependency>

 

posted @ 2020-12-08 13:03  _Gateway  阅读(96)  评论(0编辑  收藏  举报