设计模式之代理模式

代理模式

代理模式有动态代理和静态代理:静态代理模式中代理类是自己已经定理好的,在程序运行前就已经编译好了,然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。*相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法* 比如说,想要在每个代理的方法前都加上一个处理方法:

JDK和CGLIB的区别

JDK动态代理只能对实现了接口的类生成代理,而不能针对类,使用的是Java反射技术实现,不需要第三方库的支持,生成比较高效。

CGLIB主要是针对一个类生成子类,覆盖其中的方法,是一种继承,并且需要第三方库asm字节码框架来支持。

静态代理

1.确定创建接口具体行为

/**
 *  确定具体得行为接口
 * */
public interface Person {

    // 上交班费
    void giveMoney();

2.被代理对象 Student 实现接口,实现接口的具体行为的方法。

/**
 * 被代理类
 */
public class Student implements Person{
    @Override
    public void giveMoney() {
        System.out.println("学生上交班费....");
    }
}

3.代理对象,因为代理对象需要去代理被代理对象,所以代理对象必须同样实现被代理对象类的接口。代理对象需要完成委托类预处理消息,消息过滤、转发,所以他必须得持有一个被代理对象,可以是继承或者是关联。

/**
 * 学生的代理类  实现消息的委托、转发
 */
public class StudentsProxy implements Person{
    // 消息的委托必须要交给被代理类,所以得关联一个被代理类
    private Student student;

    // 只会代理学生类
    public StudentsProxy(Person student){
        if (student.getClass() == Student.class){
            this.student = (Student) student;
        }
    }

    // 代替上交班费 调用被代理学生得上交班费行为
    @Override
    public void giveMoney() {
        // 代理类增加其他前置逻辑
        System.out.println("由我给你张三代缴班费吧。。。。。");
      student.giveMoney();
    }
}

4.测试

public class ProxyTest {
    public static void main(String[] args) {
        // 创建被代理类
        Student zhangSan = new Student();
        //  创建代理类并且代理张三上交班费
      Person studentsProxy  = new StudentsProxy(zhangSan);
      // 这样上缴班费就交给了学生得代理类了 用户无感知,只知道由谁能够给我实现上交班费功能即可。
      studentsProxy.giveMoney();
    }
}

动态代理

1.确定创建接口得具体行为

/**
 *  确定具体得行为接口
 * */
public interface Person {

    // 上交班费
    void giveMoney();
}

2.确定被代理对象实现接口,并且完成具体业务逻辑

/**
 * 被代理类
 */
public class Student implements Person {
    @Override
    public void giveMoney() {
        System.out.println("学生上交班费....");
    }
}

3.自定义一个InvocationHandler类,并且实现InvocationHandler接口,这个类种会持有一个被代理对象target,并且InvocationHandler中有一个invoke方法,所有执行代理对象得方法都会被替换成执行invoke方法

/**
 * @Author Tang
 **/
public class StudentInvocationHandler<T> implements InvocationHandler {

    // 持有一个被代理对象
    T target;

    // 定义一个构造器
    public StudentInvocationHandler(T target) {
        this.target = target;
    }

    /**
     * proxy:代表动态代理对象
     * method 代表正在执行得方法
     * args:代表调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行方法....");
         method.invoke(target, args);
        System.out.println("执行结束,结果为:");
        return "执行成功....";
    }
}

4.测试

public class ProxyTest {

    public static void main(String[] args) {

        // 生成一个被代理类
        Person student =  new Student();

        StudentInvocationHandler<Person> studentInvocationHandler = new StudentInvocationHandler(student);

        // 使用Proxy得静态方法创建代理类   
      // 第一个参数是我们被代理的对象 也可以写成它实现的接口 
       // 第二个 interface对象数组 表明代理类实现了这些接口 那么代理类就可以调用接口中声明的所有方法。
      // 第三个 表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上
        Person personProxy=(Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, studentInvocationHandler);
        //使用动态代理类来
        personProxy.giveMoney();

    }
}
public static Object newProxyInstance(ClassLoader loader, 
                                            Class<?>[] interfaces, 
                                            InvocationHandler h)

这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:

loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

你可能感兴趣的:(设计模式,代理模式,设计模式,java,动态代理)