代理模式(静态代理、动态代理)

代理模式的由来:当调用某个对象时,不关心是否准确获得该对象,而是只要一个能提供对应功能的对象便可,这时咱们能够为该对象提供一个代理对象,由代理对象控制对源对象的引用。java

第一.静态代理数组

常见静态代理模式:一个接口,两个实现类,分别为被代理类和代理类,代理类中进行以下操做便可
1.建立接口类型成员变量
2.构造方法中建立被代理类对象()
3.实现的接口方法中调用被代理类的实现的接口方法
示例代码以下:ide

// 被代理类
class SubjectImpl implements Subject {
    @Override
    public void action() {
        System.out.println("执行action方法体");
    }
}

// 代理类
class ProxyClass implements Subject {
    private Subject subject = new SubjectImpl();

    private void beforeHandle() {
        System.out.println("业务方法执行前执行前置加强处理");
    }

    private void afterHandle() {
        System.out.println("业务方法执行后执行后置加强处理");
    }

    @Override
    public void action() {
        this.beforeHandle();
        subject.action();
        this.afterHandle();
    }

}

public class ProxyTest {
    public static void main(String[] args) {
        ProxyClass obj = new ProxyClass();
        obj.action();
    }
}

要使用被代理类对象的方法时,只需简单的实例化代理类对象,调用此代理类对象的方法便可,实际上是方法内部调用了被代理类的方法。工具

第二.动态代理this

JDK动态代理主要用到了Proxy类和InvocationHandler接口,二者都在java.lang.reflect包下。spa

首先介绍一下Proxy类,这个类是全部动态代理类的父类,主要用到这个类的newProxyInstance()静态方法:代理

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

这个方法直接生成一个动态代理类对象,方法须要传三个参数,第一个参数是被代理类对应的类加载器对象,第二个参数是被代理类实现的一系列接口对应的Class对象组成的数组一个数组,第三个参数是一个InvocationHandler对象(一个InvocationHandler实现类对象)。code

InvocationHander接口就只有一个方法:对象

public Object invoke(Object proxy, Method method, Object[] args)

咱们得自定义一个InvocationHander接口实现类,重写invoke()方法。blog

JDK动态代理代码示例:

//接口
interface Subject {
    public void doSomething(String str);
}

// 接口实现类
class RealSubject implements Subject {
    @Override
    public void doSomething(String str) {
        System.out.println("Subject接口实现类RealSubject实现doSomething方法()");
    }
}

// InvocationHandler接口实现类
class MyIncovationHandler implements InvocationHandler {
    private Object proxied;

    // 构造器参数是被代理类对象
    public MyIncovationHandler(Object proxied) {
        this.proxied = proxied;
    }

    public MyIncovationHandler() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        method.invoke(proxied, args);
        after();
        return null;
    }

    // 加强处理方法,能够抽出到一个单独的工具类里面
    private void before() {
        System.out.println("Before处理");
    }

    private void after() {
        System.out.println("After处理");
    }
}

public class JdkDynamicProxyTest {
    public static void main(String args[]) {
        Subject s = new RealSubject();
        Object obj = Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),
                new MyIncovationHandler(s));
        Subject subject = (Subject) obj;
        subject.doSomething("kou");
    }
}

     上例中,有一个RealSubject类,实现了接口Subject。InvocationHander接口的实现类MyInvocationHander,重写了invoke方法,在方法体中调用第二个参数method的invoke方法,method的invoke方法须要两个参数,第一个参数是被代理类的实例,第二个参数是参数列表,是invoke方法的第三个参数。这里被代理类的实例不建议直接new出来一个实例而后传进去,而是建议在建立InvocationHander实例时把被代理类实例传进来,这样比较解耦。

      编译上Proxy.newProxyInstance()的返回值类型是Object,但其实运行时类型是动态代理类的类型($Proxy开头的类),又由于实现了代理类所实现的所有接口,因此能够强转为任意一个所实现的接口类型。这个时候调用该接口的方法,底层就会执行接口实现类对应的实现。

      Proxy的newProxyInstance()方法的第二个参数是接口对应的Class对象组成的数组,而不是被代理类的Class对象。因此说,JDK动态代理创建在接口之上的。那么,若是被代理类没有实现任何接口,就不能用JDK动态代理了,须要用到cglib动态代理。cglib动态代理实际上是对被代理类建立一个子类,让这个子类去代理父类,因此要求被代理类不能是final的。

相关文章
相关标签/搜索