
com.alibaba.dubbo.common.bytecode.Proxy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo2 Show documentation
Show all versions of dubbo2 Show documentation
The all in one project of dubbo2
The newest version!
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common.bytecode;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.common.utils.ReflectUtils;
/**
* Proxy.
*
* @author qian.lei
*/
public abstract class Proxy
{
private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ return null; }
};
public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented."); }
};
private static final Map> ProxyCacheMap = new WeakHashMap>();
private static final Object PendingGenerationMarker = new Object();
/**
* Get proxy.
*
* @param ics interface class array.
* @return Proxy instance.
*/
public static Proxy getProxy(Class... ics)
{
return getProxy(ClassHelper.getCallerClassLoader(Proxy.class), ics);
}
/**
* Get proxy.
* @param cl class loader.
* @param ics interface class array.
*
* @return Proxy instance.
*/
public static Proxy getProxy(ClassLoader cl, Class... ics)
{
if( ics.length > 65535 )
throw new IllegalArgumentException("interface limit exceeded");
StringBuilder sb = new StringBuilder();
for(int i=0;i tmp = null;
try
{
tmp = Class.forName(itf, false, cl);
}
catch(ClassNotFoundException e)
{}
if( tmp != ics[i] )
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
sb.append(itf).append(';');
}
// use interface class name list as key.
String key = sb.toString();
// get cache by class loader.
Map cache;
synchronized( ProxyCacheMap )
{
cache = ProxyCacheMap.get(cl);
if( cache == null )
{
cache = new HashMap();
ProxyCacheMap.put(cl, cache);
}
}
Proxy proxy = null;
synchronized( cache )
{
do
{
Object value = cache.get(key);
if( value instanceof Reference )
{
proxy = (Proxy)((Reference)value).get();
if( proxy != null )
return proxy;
}
if( value == PendingGenerationMarker )
{
try{ cache.wait(); }catch(InterruptedException e){}
}
else
{
cache.put(key, PendingGenerationMarker);
break;
}
}
while( true );
}
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try
{
ccp = ClassGenerator.newInstance(cl);
Set worked = new HashSet();
List methods = new ArrayList();
for(int i=0;i rt = method.getReturnType();
Class[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for(int j=0;j[]{ InvocationHandler.class }, new Class[0], "handler=$1;");
ccp.addDefaultConstructor();
Class clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class pc = ccm.toClass();
proxy = (Proxy)pc.newInstance();
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
// release ClassGenerator
if( ccp != null )
ccp.release();
if( ccm != null )
ccm.release();
synchronized( cache )
{
if( proxy == null )
cache.remove(key);
else
cache.put(key, new WeakReference(proxy));
cache.notifyAll();
}
}
return proxy;
}
/**
* get instance with default handler.
*
* @return instance.
*/
public Object newInstance()
{
return newInstance(THROW_UNSUPPORTED_INVOKER);
}
/**
* get instance with special handler.
*
* @return instance.
*/
abstract public Object newInstance(InvocationHandler handler);
protected Proxy(){}
private static String asArgument(Class cl, String name)
{
if( cl.isPrimitive() )
{
if( Boolean.TYPE == cl )
return name + "==null?false:((Boolean)" + name + ").booleanValue()";
if( Byte.TYPE == cl )
return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
if( Character.TYPE == cl )
return name + "==null?(char)0:((Character)" + name + ").charValue()";
if( Double.TYPE == cl )
return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
if( Float.TYPE == cl )
return name + "==null?(float)0:((Float)" + name + ").floatValue()";
if( Integer.TYPE == cl )
return name + "==null?(int)0:((Integer)" + name + ").intValue()";
if( Long.TYPE == cl )
return name + "==null?(long)0:((Long)" + name + ").longValue()";
if( Short.TYPE == cl )
return name + "==null?(short)0:((Short)" + name + ").shortValue()";
throw new RuntimeException(name+" is unknown primitive type.");
}
return "(" + ReflectUtils.getName(cl) + ")"+name;
}
}