动态Proxy

代理模式

2019-08-17  本文已影响0人  晓晓桑

概述

为其他对象提供一种代理,用以控制对这个对象对访问

分类

静态代理、动态代理

静态代理

image.png
AbstractObject接口
public interface IAbstract {
    public void operation();
}
ProxyObject 代理类,实现接口

在代理类里面对被代理类调用operation()方法前后可以加更多逻辑限制。
例如:在开发过程中,想要对原有的方法做改进,方法一:直接改原来的方法,方法二:调用代理类,对产生的结果进行控制,这就是代理模式

//代理类
public class ProxyI implements IAbstract {

    //被代理类对象
    RealI mRealObject;

    public ProxyI(RealI mRealObject) {
        this.mRealObject = mRealObject;
    }

    @Override
    public void operation() {
        if (mRealObject == null) {
            mRealObject = new RealI();
        }
        //在代理类里面对被代理类调用operation()方法前后可以加更多逻辑限制。
        //例如:在开发过程中,想要对原有对方法做改进,方法一:直接改原来对方法,方法二:调用代理类,对产生对结果进行控制,这就是代理模式
        mRealObject.operation();
       System.out.println("ProxyI: operation()");

    }
}
被代理类,同样实现接口
//被代理类
public class RealI implements IAbstract {

    @Override
    public void operation() {
          System.out.println("RealI: operation()");
    }
}
测试类
public class ProxyTest {
    public static void main(String[] args) {
        //
        RealI realObject = new RealI();
        ProxyI father = new ProxyI(realObject);
        father.operation();
    }
}

运行结果:


image.png

动态代理

什么是动态代理?
代理类是在程序运行时创建的代理方式,代理类他不是在java代码中定义的,而是程序运行时,根据我们在java代码中的配置动态生成的。相比于静态代理,他可以很方便的对代理类的函数进行统一处理,而不用频繁修改每一个代理类的函数(根据你的业务逻辑)

jdk动态代理

动态代理的实现:

所要实现的接口

//所要实现的接口
public interface ISubject {
    void shopping();
}

被代理类

//被代理类
public class Man implements ISubject {
    @Override
    public void shopping() {
        System.out.println("Man :Man Shopping");
    }
}

代理类

//代理类

//动态代理的代理类 必须要实现InvocationHandler接口,并且每个代理类的实例都关联到了一个handler。
//代理对象调用程序的时候,一定要实现的接口,
// 当通过代理对象调用方法的时候,
// 这个方法就会把他指派到InvocationHandler的invoke(Object proxy, Method method, Object[] args)上
public class Proxy implements InvocationHandler {

    private Object target;//要代理的真实对象

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

    //Object proxy:  指代我们所代理的那个真实对象(真实对象就是被代理对象)
    //Method method:  指代的是我们所要调用真实对象的某个方法的Method对象
    //Object[] args:   指代的是调用真实对象某个方法时接受的所有参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy :" + proxy.getClass().getName());
        System.out.println("proxy :method: " + method);

        //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("proxy :在代理真实对象前我们可以添加一些自己的操作");

        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(target, args);

        //在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("proxy :在代理真实对象后我们也可以添加一些自己的操作");
        return null;
    }
}

实现接口方法

public class ProxyTest {
    public static void main(String[] args) {
        //被代理者
        ISubject man = new Man();
        //代理者
        Proxy proxy = new Proxy(man);

        //首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?
        //原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象proxy提供了一组什么接口,那么我这个代理对象proxy就会实现了这组接口,
        //这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是ISubject类型,所以就可以将其转化为ISubject类型了。
        ISubject subject = (ISubject) java.lang.reflect.Proxy
                .newProxyInstance(man.getClass().getClassLoader(), man.getClass().getInterfaces(), proxy);

        System.out.println("ProxyTest " + subject.getClass().getName());
        //代理对象调用接口方法时,会关联到InvocationHandler到invoke中的方法去执行
        subject.shopping();
    }
}

InvocationHandler类源码

public interface InvocationHandler {
    //Object proxy:  指代我们所代理的那个真实对象(真实对象就是被代理对象)
    //Method method:  指代的是我们所要调用真实对象的某个方法的Method对象
    //Object[] args:   指代的是调用真实对象某个方法时接受的所有参数
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

newProxyInstance

java.lang.reflect.Proxy作用是动态创建一个对象的类,他提供了很多方法我们用的最多的就是 newProxyInstance 这个方法

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            throws IllegalArgumentException {
    Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
 /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
 try {
 final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
 cons.setAccessible(true);
   }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException | InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
  }
动态代理总结

调用java.lang.reflect.Proxy类的newProxyInstanced(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法,他会根据我们传递来的class对象,生成一个代理类,每当代理类执行接口方法的时候,就会调用InvocationHandler里面的invoke(Object proxy, Method method, Object[] args)方法,在invoke方法中可以执行想要的操作,这就是动态代理。
注意⚠️:

CFLIB动态代理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。详解有待更新。

上一篇 下一篇

猜你喜欢

热点阅读