private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces); // 如果实现给定接口的给定加载器所定义的代理类存在,则从缓存取,否则通过ProxyClassFactory创建
}
上述代码主要做了两件事:
判断代理类实现的接口不能大于65535这个数;
缓存存在代理类,则从缓存取,否则从ProxyClassFactory创建。
3. WeakCache源码
下面将继续深入WeakCache的源码,分析proxyClassCache.get方法相关实现。
final class WeakCache {
private final ReferenceQueue refQueue
= new ReferenceQueue<>(); // Reference引用队列
// the key type is Object for supporting null key
private final ConcurrentMap
/**
* A factory {@link Supplier} that implements the lazy synchronized
* construction of the value and installment of it into the cache.
*/
private final class Factory implements Supplier {
private final K key; //一级缓存key, 根据ClassLoader生成
private final P parameter; //代理类实现的接口数组
private final Object subKey; //二级缓存key, 根据接口数组生成
private final ConcurrentMap> valuesMap; //二级缓存
Factory(K key, P parameter, Object subKey,
ConcurrentMap> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@Override
public synchronized V get() { // serialize access
// re-check
Supplier supplier = valuesMap.get(subKey); //再次检查并获取二级缓存里面的Supplier, 用来验证是否是Factory本身
if (supplier != this) { //在这里验证supplier是否是Factory实例本身, 如果不是则返回null让调用者继续轮询重试;
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter)); // 通过valueFactory生成代理类, 实际传入ProxyClassFactory去生成代理类
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this); //如果生成代理类失败, 就将这个二级缓存删除
}
}
// the only path to reach here is with non-null value
assert value != null; //只有value的值不为空才能到达这里
// wrap value with CacheValue (WeakReference)
CacheValue cacheValue = new CacheValue<>(value); //使用弱引用包装生成的代理类
// put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE); //将包装后的cacheValue作为可用的代理类,放入reverseMap中
// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) { //将包装后的cacheValue放入二级缓存中, 这个操作必须成功, 否则就报错
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value; //最后返回未被弱引用包装的原始代理类value
}
}
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction[], Class>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy"; // 所有代理类名称的前缀
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong(); // 用原子类来生成代理类的序号, 生成唯一的代理类名称
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) { // intf是否可以由指定的类加载进行加载
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) { // intf是否是一个接口
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { // intf在数组中是否有重复
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in //生成代理类的包名
int accessFlags = Modifier.PUBLIC | Modifier.FINAL; //生成代理类的访问标志, 默认是public final的
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class> intf : interfaces) {
int flags = intf.getModifiers(); //获取接口的访问标志
if (!Modifier.isPublic(flags)) { //如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同
accessFlags = Modifier.FINAL; //生成的代理类的访问标志设置为final
String name = intf.getName(); //获取接口全限定名
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg; //生成的代理类的包名和接口包名是一样的
} else if (!pkg.equals(proxyPkg)) { //代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; //如果接口访问标志都是public的话, 那生成的代理类都放到默认的包下:com.sun.proxy
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement(); //生成代理类的序号
String proxyName = proxyPkg + proxyClassNamePrefix + num; //生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags); // 用ProxyGenerator来生成字节码, 该类放在sun.misc包下
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length); //根据二进制文件生成相应的Class实例
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
/**
* Generate a class file for the proxy class. This method drives the
* class file generation process.
*/
private byte[] generateClassFile() {
/* ============================================================
* Step 1: Assemble ProxyMethod objects for all methods to
* generate proxy dispatching code for.
*/
//第一步, 将所有的方法组装成ProxyMethod对象
/*
* Record that proxy methods are needed for the hashCode, equals,
* and toString methods of java.lang.Object. This is done before
* the methods from the proxy interfaces so that the methods from
* java.lang.Object take precedence over duplicate methods in the
* proxy interfaces.
*/
addProxyMethod(hashCodeMethod, Object.class); //为代理类生成hashCode代理方法
addProxyMethod(equalsMethod, Object.class); //为代理类生成equals代理方法
addProxyMethod(toStringMethod, Object.class); //为代理类生成toString代理方法
/*
* Now record all of the methods from the proxy interfaces, giving
* earlier interfaces precedence over later ones with duplicate
* methods.
*/
for (Class> intf : interfaces) { //遍历每一个接口的每一个方法, 并且为其生成ProxyMethod对象
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
/*
* For each set of proxy methods with the same signature,
* verify that the methods' return types are compatible.
*/
for (List sigmethods : proxyMethods.values()) { //对于具有相同签名的代理方法, 检验方法的返回值是否兼容
checkReturnTypes(sigmethods);
}
/* ============================================================
* Step 2: Assemble FieldInfo and MethodInfo structs for all of
* fields and methods in the class we are generating.
*/ //第二步, 组装要生成的class文件的所有的字段信息和方法信息
try {
methods.add(generateConstructor()); //添加构造器方法
for (List sigmethods : proxyMethods.values()) { //遍历缓存中的代理方法
for (ProxyMethod pm : sigmethods) {
// add static field for method's Method object
fields.add(new FieldInfo(pm.methodFieldName, //添加代理类的静态字段
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// generate code for proxy method and add it
methods.add(pm.generateMethod()); //添加代理类的代理方法
}
}
methods.add(generateStaticInitializer()); //添加代理类的静态字段初始化方法
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) { //验证方法和字段集合不能大于65535
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
/* ============================================================
* Step 3: Write the final class file.
*/
//第三步, 写入最终的class文件
/*
* Make sure that constant pool indexes are reserved for the
* following items before starting to write the final class file.
*/
cp.getClass(dotToSlash(className)); //验证常量池中存在代理类的全限定名
cp.getClass(superclassName); //验证常量池中存在代理类父类的全限定名, 父类名为:"java/lang/reflect/Proxy"
for (Class> intf: interfaces) { //验证常量池存在代理类接口的全限定名
cp.getClass(dotToSlash(intf.getName()));
}
/*
* Disallow new constant pool additions beyond this point, since
* we are about to write the final constant pool table.
*/
cp.setReadOnly(); //接下来要开始写入文件了,设置常量池只读
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
/*
* Write all the items of the "ClassFile" structure.
* See JVMS section 4.1.
*/
// u4 magic;
dout.writeInt(0xCAFEBABE); //1.写入魔数
// u2 minor_version;
dout.writeShort(CLASSFILE_MINOR_VERSION); //2.写入次版本号
// u2 major_version;
dout.writeShort(CLASSFILE_MAJOR_VERSION); //3.写入主版本号
cp.write(dout); // (write constant pool) //4.写入常量池
// u2 access_flags;
dout.writeShort(accessFlags); //5.写入访问修饰符
// u2 this_class;
dout.writeShort(cp.getClass(dotToSlash(className))); //6.写入类索引
// u2 super_class;
dout.writeShort(cp.getClass(superclassName)); //7.写入父类索引, 生成的代理类都继承自Proxy
// u2 interfaces_count;
dout.writeShort(interfaces.length); //8.写入接口计数值
// u2 interfaces[interfaces_count];
for (Class> intf : interfaces) {
dout.writeShort(cp.getClass( //9.写入接口集合
dotToSlash(intf.getName())));
}
// u2 fields_count;
dout.writeShort(fields.size()); //10.写入字段计数值
// field_info fields[fields_count];
for (FieldInfo f : fields) {
f.write(dout); //11.写入字段集合
}
// u2 methods_count;
dout.writeShort(methods.size());//12.写入方法计数值
// method_info methods[methods_count];
for (MethodInfo m : methods) {
m.write(dout); //13.写入方法集合
}
// u2 attributes_count;
dout.writeShort(0); // (no ClassFile attributes for proxy classes) //14.写入属性计数值, 代理类class文件没有属性所以为0
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray(); //转换成二进制数组输出
}
//关键字的使用探讨/*访问关键词private 只能在本类中访问public 只能在本工程中访问protected 只能在包中和子类中访问默认的 只能在包中访问*//*final 类 方法 变量 final 类 不能被继承 final 方法 不能被子类覆盖,但可以继承 final 变量 只能有一次赋值,赋值后不能改变 final 不能用来修饰构造方法*///this()
What’s new in Zabbix 2.0?
去年开始使用Zabbix的时候,是1.8.X的版本,今年Zabbix已经跨入了2.0的时代。看了2.0的release notes,和performance相关的有下面几个:
:: Performance improvements::Trigger related da
修改jboss端口
%JBOSS_HOME%\server\{服务实例名}\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml
中找到
<!-- The ports-default bindings are obtained by taking the base bindin
@echo off
::演示:删除指定路径下指定天数之前(以文件名中包含的日期字符串为准)的文件。
::如果演示结果无误,把del前面的echo去掉,即可实现真正删除。
::本例假设文件名中包含的日期字符串(比如:bak-2009-12-25.log)
rem 指定待删除文件的存放路径
set SrcDir=C:/Test/BatHome
rem 指定天数
set DaysAgo=1
HTML5的video和audio标签是用来在网页中加入视频和音频的标签,在支持html5的浏览器中不需要预先加载Adobe Flash浏览器插件就能轻松快速的播放视频和音频文件。而html5media.js可以在不支持html5的浏览器上使video和audio标签生效。 How to enable <video> and <audio> tags in