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