一直想分享一些技術,為多變的技術帶來一些分享,以後會慢慢的帶來一些自己學過的技術,和自己的一些心得,最近想分享effect java,設計模式,并發程式設計,一些java集合源碼和并發包源碼,jvm,mybatis源碼,nio,nio2,netty,grpc,和一些資料結構算法,mysql,git
今天就先來分析靜态代理和動态代理
一、靜态代理模式
假設有個這樣的場景,想對一個Source類進行加強,比如在不改變Source類的基礎,執行Source類的method()方法執行前後列印一些日記,實作步驟
- 首先有個接口
public interface Sourceable { void method(); }複制代碼
- 再者實作接口的Source類
public class Source implements Sourceable { @Override public void method() { System.out.println("the original method"); } }複制代碼
- 然後再有個代理類,同樣也實作Sourceable接口
public class Proxy implements Sourceable { private Sourceable source; public Proxy(Source source) { this.source = source; } @Override public void method() { before(); source.method(); after(); } private void before() { System.out.println("method() run begin"); } private void after() { System.out.println("method() run end"); } }複制代碼
- 最後測試下
public class ProxyTest { public static void main(String[] args) { Source source = new Source(); Proxy proxy = new Proxy(source); proxy.method(); } }複制代碼
- 結果
method() run begin the original method method() run end 複制代碼
二、動态代理模式
我們經常在使用mybatis的時候mapper隻是個接口,調用接口方法就能執行如下
IUserMapper userMapper = session.getMapper(IUserMapper.class);//擷取接口,已經是代理接口
userMapper.getById(1);//調用mybatis内部的MapperProxy類的invoke
複制代碼
我們先來看下核心的Proxy.newProxyInstance(arg1,arg2,arg3)方法
第一個參數arg1是接口的classloader,就是為了加載動态生成的代理類,arg2是接口,為了生成的代理類實作此接口,擁有實作此接口的方法,最後一個參數arg3,InvocationHandler,目的是生成的代理類對象,執行方法時,調用此内部的invoke()方法
接下來我們開始實作它,有兩種情況,一種是接口有實作類,我們在内部直接用反射進行調用實作類方法,第二種就是mybatis實作方式,隻有接口沒有實作類,我們先實作由實作類的方式
- 首先有個ServiceInterface接口
public interface ServiceInterface { void println(); }複制代碼
- 再者有個接口實作類
public class ServiceInterfaceImpl implements ServiceInterface { @Override public void println() { System.out.println("ServiceInterfaceImpl"); } }複制代碼
- 接下來看下重要的handler,invoke有三個參數第一個動态生成的代理類,第二個參數是要執行的方法,第三個參數是方法參數
public class MyInvocationHandler implements java.lang.reflect.InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("2222");
method.invoke(target, args);
System.out.println("3333");
return null;
}
}複制代碼
- 最後測試
public class ProxyTest { public static void main(String[] args) { ServiceInterface serviceInterface = new ServiceInterfaceImpl(); InvocationHandler InvocationHandler = new MyInvocationHandler(serviceInterface); ServiceInterface proxy = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), serviceInterface.getClass().getInterfaces(), InvocationHandler); proxy.println(); } }複制代碼
我們再來看下第二種方式隻有接口沒有實作類
- 同樣首先有個接口
public interface ServiceInterface { void println(); }複制代碼
- 再者
public class MyInvocationHandler implements java.lang.reflect.InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("2222");
System.out.println("3333");
return null;
}
}複制代碼
- 最後測試
public class ProxyTest { public static void main(String[] args) { InvocationHandler InvocationHandler = new MyInvocationHandler(); ServiceInterface proxy = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), new Class[]{ServiceInterface.class}, InvocationHandler); proxy.println(); } }複制代碼
三、總結
流程是調用Proxy.newProxyInstance()方法會動态生成實作傳入的第二個參數的接口,然後第三個參數是handler,調用proxy.println(),其實動态類println()方法其實是調handler的invoke方法,我們接下來看下反編譯後的動态類
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) fieldsfirst
package com.sun.proxy;
import java.lang.reflect.*;
import proxyStudy.ServiceInterface;
public final class $Proxy0 extends Proxy
implements ServiceInterface
{
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final void println()
{
try
{
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
static
{
try
{
m3 = Class.forName("proxyStudy.ServiceInterface").getMethod("println", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
複制代碼
轉載于:https://juejin.im/post/5bff9d17e51d45454b412116