java动态代理

来源:互联网 发布:高音 知乎 编辑:程序博客网 时间:2024/06/05 15:05

1、代理模式代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。

2、静态代理的两种实现方式:

(1)继承法:直接继承被代理类,实现其原有方法,并添加一些额外功能。

(2)聚合法:代理类实现被代理类相同功能的接口,并声明一个被代理对象的成员变量。

无论采用哪种方法,静态代理的代理类需要运行前开发完毕,而动态代理的代理类是运行时生成的。

3、动态代理的两种实现

(1)jdk的proxy:被代理类必须实现某个接口。

(2)CGLIB:第三方提供的,底层实现是ASM,直接更改类的字节码实现动态代理,对被代理类无特殊要求。

4、jdk中的动态代理——proxy

通过一个简单的例子说明

接口UserDao

public interface UserDao {public void add(String name);public void delete(String name);public void update(String name,int age);public List<String> search(int age);}

被代理类UserDaoImpl

public class UserDaoImpl implements UserDao {public void add(String name) {System.out.println("新增用户"+name);}public void delete(String name) {System.out.println("删除用户"+name);}public void update(String name, int age) {System.out.println("修改用户"+name+"的年龄为"+age);}public List<String> search(int age) {List<String> users=new ArrayList<String>();users.add("小红");users.add("小绿");users.add("小蓝");System.out.println("查询年龄为"+age+"的用户名字,查询结果列表为:"+users);return users;}}


TransactionInvocationHandler类实现InvocationHandler

public class TransactionInvocationHandler implements InvocationHandler{        //被代理对象private Object target;public TransactionInvocationHandler(Object target) {super();this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用被代理对象方法之前执行的操作                System.out.println("事务开启");                //通过反射机制,调用被代理对象方法Object result=method.invoke(target, args);                //调用被代理对象方法之后执行的操作System.out.println("事务提交");return result;}}

调用Proxy的静态方法生成代理对象,并调用代理对象的相关方法

//被代理对象,最终要调用的UserDao userDao=new UserDaoImpl();//生成代理对象UserDao proxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new TransactionInvocationHandler(userDao));//调用代理对象的方法   proxy.add("小红");proxy.delete("小红");proxy.update("小红", 18);proxy.search(18);

运行结果

事务开启
新增用户小红
事务提交
事务开启
删除用户小红
事务提交
事务开启
修改用户小红的年龄为18
事务提交
事务开启
查询年龄为18的用户名字,查询结果列表为:[小红, 小绿, 小蓝]
事务提交

5、newProxyInstance方法内部,首先生成一个代理类的字节码对象,创建代理对象。该代理类继承了Proxy类并实现了UserDao接口。以下代码可以将该类的字节码输出到文件并

Class cls=proxy.getClass();System.out.println(cls.toGenericString());byte[] buffer=ProxyGenerator.generateProxyClass("$Proxy0", userDao.getClass().getInterfaces());OutputStream out=new FileOutputStream(new File("E:\\$Proxy0.class"));out.write(buffer);out.flush();out.close();

反编译以后的源码是:

public final class $Proxy0 extends Proxy  implements UserDao{  private static Method m1;  private static Method m2;  private static Method m3;  private static Method m5;  private static Method m6;  private static Method m0;  private static Method m4;  public $Proxy0(InvocationHandler paramInvocationHandler)    throws   {    super(paramInvocationHandler);  }  public final boolean equals(Object paramObject)    throws   {    try    {      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final String toString()    throws   {    try    {      return (String)this.h.invoke(this, m2, null);    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final void add(String paramString)    throws   {    try    {      this.h.invoke(this, m3, new Object[] { paramString });      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final void delete(String paramString)    throws   {    try    {      this.h.invoke(this, m5, new Object[] { paramString });      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final List search(int paramInt)    throws   {    try    {      return (List)this.h.invoke(this, m6, new Object[] { Integer.valueOf(paramInt) });    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final int hashCode()    throws   {    try    {      return ((Integer)this.h.invoke(this, m0, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final void update(String paramString, int paramInt)    throws   {    try    {      this.h.invoke(this, m4, new Object[] { paramString, Integer.valueOf(paramInt) });      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  static  {    try    {      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);      m3 = Class.forName("proxy.UserDao").getMethod("add", new Class[] { Class.forName("java.lang.String") });      m5 = Class.forName("proxy.UserDao").getMethod("delete", new Class[] { Class.forName("java.lang.String") });      m6 = Class.forName("proxy.UserDao").getMethod("search", new Class[] { Integer.TYPE });      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);      m4 = Class.forName("proxy.UserDao").getMethod("update", new Class[] { Class.forName("java.lang.String"), Integer.TYPE });      return;    }    catch (NoSuchMethodException localNoSuchMethodException)    {      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());    }    catch (ClassNotFoundException localClassNotFoundException)    {      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());    }  }}

可以看到,调用代理类的add方法,最终调用了父类Proxy成员InvocationHandler的invoke方法,并且把add方法所对应的Method对象以及用户传递的参数、代理对象本身作为参数传递给invoke方法。


newProxyInstance源码,可以看到,其中最核心的就是Class<?> cl = getProxyClass0(loader, intfs);  生成了一个代表代理类的字节码对象,接下来就可以用反射的方式生成代理对象了,cons.newInstance(new Object[]{h});这行代码其实是调用了父类Proxy的构造方法生成一个代理对象,该构造方法将我们传递的InvocationHandler对象赋值给Proxy的成员变量h。getProxyClass0(loader, intfs)底层调用sun.misc.ProxyGenerator.generateProxyClass(String,Class<?>[])。

 @CallerSensitive    public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException    {        Objects.requireNonNull(h);        final Class<?>[] intfs = interfaces.clone();        final SecurityManager sm = System.getSecurityManager();        if (sm != null) {            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);        }        /*         * Look up or generate the designated proxy class.         */        Class<?> cl = getProxyClass0(loader, intfs);        /*         * Invoke its constructor with the designated invocation handler.         */        try {            if (sm != null) {                checkNewProxyPermission(Reflection.getCallerClass(), cl);            }            final Constructor<?> cons = cl.getConstructor(constructorParams);            final InvocationHandler ih = h;            if (!Modifier.isPublic(cl.getModifiers())) {                AccessController.doPrivileged(new PrivilegedAction<Void>() {                    public Void run() {                        cons.setAccessible(true);                        return null;                    }                });            }            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);        }    }







0 0