具體場景
爲了使代理類與被代理類對第三方有相同的函數,代理類與被代理類一般實現一個公共的interface,定義如下
public interface Subject {
void rent();
void hello(String s);
}
被代理類定義如下
public class RealSubject implements Subject {
@Override
public void rent() {
System.out.println("I want to rent my house");
}
@Override
public void hello(String s) {
System.out.println("hello :"+s);
}
}
代理需求:在接口subject的每個方法前後分別輸出before invoke和after invoke
靜態代理解決方案
public class StaticSubjectProxy implements Subject {
private RealSubject realSubject;
@Override
public void rent() {
System.out.println("before invoke");
realSubject.rent();
System.out.println("after invoke");
}
@Override
public void hello(String s) {
System.out.println("before invoke");
realSubject.hello(s);
System.out.println("after invoke");
}
}
但是這種處理存在弊端,如果subject接口的方法不止兩個,還有很多其他的方法,那麼靜態代理的實現就不太適合
動態代理解決方案
public class SubjectInvocationHandler implements InvocationHandler {
private Subject subject; //被代理類
public SubjectInvocationHandler(Subject interfaceClass) {
this.subject = interfaceClass;
}
/**
*
* @param proxy 動態代理類的引用,通常情況下不需要它。但可以使用getClass()方法,
* 得到proxy的Class類從而取得實例的類信息,如方法列表,annotation等。
* @param method 方法對象的引用,代表被動態代理類調用的方法。從中可得到方法名,參數類型,返回類型等等
* @param args args對象數組,代表被調用方法的參數。注意基本類型(int,long)會被裝箱成對象類型(Interger, Long)
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!isDefaultMethod(method)){
System.out.println("before invoke");
System.out.println("Method: " + method);
//執行被代理類方法
method.invoke(subject,args);
System.out.println("after invoke");
}
return null;
}
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
生成代理類方法
public class SubjectProxy {
private Subject subject;
public SubjectProxy(Subject subject) {
this.subject = subject;
}
public Subject create(){
final Class<?>[] interfaces = new Class[]{Subject.class};
final SubjectInvocationHandler handler = new SubjectInvocationHandler(subject);
return (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),interfaces,handler);
}
}
@Test
public void test(){
Subject subject = new RealSubject();
SubjectProxy proxy = new SubjectProxy(subject);
Subject proxySubject = proxy.create();
proxySubject.rent();
proxySubject.hello("world");
}
上述動態代理無論subject包含多少方法,動態代理只需實現一次。 mybatis獲取mapper,使用到動態代理
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
參考: