Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
471fbf7e
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
471fbf7e
编写于
10月 30, 2009
作者:
T
Thomas Risberg
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added classes from contributed patch for load-time weaving in JBoss 5 (SPR-5764)
上级
14e7b461
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
484 addition
and
0 deletion
+484
-0
org.springframework.context/ivy.xml
org.springframework.context/ivy.xml
+2
-0
org.springframework.context/pom.xml
org.springframework.context/pom.xml
+12
-0
org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
...amework/context/weaving/DefaultContextLoadTimeWeaver.java
+4
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ClassFileTransformer2Translator.java
...t/classloading/jboss/ClassFileTransformer2Translator.java
+50
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss50ClassLoader.java
...ork/instrument/classloading/jboss/JBoss50ClassLoader.java
+78
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss51ClassLoader.java
...ork/instrument/classloading/jboss/JBoss51ClassLoader.java
+37
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5ClassLoader.java
...work/instrument/classloading/jboss/JBoss5ClassLoader.java
+120
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java
...k/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java
+120
-0
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ReflectionHelper.java
...ework/instrument/classloading/jboss/ReflectionHelper.java
+59
-0
org.springframework.context/template.mf
org.springframework.context/template.mf
+2
-0
未找到文件。
org.springframework.context/ivy.xml
浏览文件 @
471fbf7e
...
...
@@ -46,6 +46,8 @@
<dependency
org=
"org.aspectj"
name=
"com.springsource.org.aspectj.weaver"
rev=
"1.6.5.RELEASE"
conf=
"optional, aspectj->compile"
/>
<dependency
org=
"org.beanshell"
name=
"com.springsource.bsh"
rev=
"2.0.0.b4"
conf=
"optional, beanshell->compile"
/>
<dependency
org=
"org.codehaus.groovy"
name=
"com.springsource.org.codehaus.groovy"
rev=
"1.6.3"
conf=
"optional, groovy->compile"
/>
<dependency
org=
"org.jboss.cl"
name=
"com.springsource.org.jboss.classloader"
rev=
"2.0.5.GA"
conf=
"provided->compile"
/>
<dependency
org=
"org.jboss.util"
name=
"com.springsource.org.jboss.util"
rev=
"2.2.13.GA"
conf=
"provided->compile"
/>
<dependency
org=
"org.joda"
name=
"com.springsource.org.joda.time"
rev=
"1.6.0"
conf=
"optional->compile"
/>
<dependency
org=
"org.jruby"
name=
"com.springsource.org.jruby"
rev=
"1.2.0"
conf=
"optional, jruby->compile"
/>
<dependency
org=
"org.springframework"
name=
"org.springframework.asm"
rev=
"latest.integration"
conf=
"compile->compile"
/>
...
...
org.springframework.context/pom.xml
浏览文件 @
471fbf7e
...
...
@@ -129,6 +129,18 @@
<version>
1.6
</version>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.jboss.cl
</groupId>
<artifactId>
com.springsource.org.jboss.classloader
</artifactId>
<version>
2.0.5.GA
</version>
<scope>
provided
</scope>
</dependency>
<dependency>
<groupId>
org.jboss.util
</groupId>
<artifactId>
com.springsource.org.jboss.util
</artifactId>
<version>
2.2.13.GA
</version>
<scope>
provided
</scope>
</dependency>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-asm
</artifactId>
...
...
org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
浏览文件 @
471fbf7e
...
...
@@ -27,6 +27,7 @@ import org.springframework.instrument.InstrumentationSavingAgent;
import
org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver
;
import
org.springframework.instrument.classloading.LoadTimeWeaver
;
import
org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
;
import
org.springframework.instrument.classloading.jboss.JBoss5LoadTimeWeaver
;
import
org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver
;
import
org.springframework.instrument.classloading.oc4j.OC4JLoadTimeWeaver
;
import
org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver
;
...
...
@@ -105,6 +106,9 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
else
if
(
classLoader
.
getClass
().
getName
().
startsWith
(
"com.sun.enterprise"
))
{
return
new
GlassFishLoadTimeWeaver
(
classLoader
);
}
else
if
(
classLoader
.
getClass
().
getName
().
startsWith
(
"org.jboss"
))
{
return
new
JBoss5LoadTimeWeaver
(
classLoader
);
}
}
catch
(
IllegalStateException
ex
)
{
logger
.
info
(
"Could not obtain server-specific LoadTimeWeaver: "
+
ex
.
getMessage
());
...
...
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ClassFileTransformer2Translator.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
java.security.ProtectionDomain
;
import
java.lang.instrument.ClassFileTransformer
;
import
org.jboss.util.loading.Translator
;
/**
* ClassFileTransfomer to Translator bridge.
*
* @author Ales Justin
*/
public
class
ClassFileTransformer2Translator
implements
Translator
{
private
ClassFileTransformer
transformer
;
public
ClassFileTransformer2Translator
(
ClassFileTransformer
transformer
)
{
if
(
transformer
==
null
)
{
throw
new
IllegalArgumentException
(
"Null transformer"
);
}
this
.
transformer
=
transformer
;
}
public
byte
[]
transform
(
ClassLoader
loader
,
String
className
,
Class
<?>
classBeingRedefined
,
ProtectionDomain
protectionDomain
,
byte
[]
classfileBuffer
)
throws
Exception
{
return
transformer
.
transform
(
loader
,
className
,
classBeingRedefined
,
protectionDomain
,
classfileBuffer
);
}
public
void
unregisterClassLoader
(
ClassLoader
loader
)
{
}
}
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss50ClassLoader.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
java.lang.reflect.Method
;
import
org.jboss.classloader.spi.ClassLoaderSystem
;
import
org.jboss.classloader.spi.base.BaseClassLoader
;
import
org.jboss.classloader.spi.base.BaseClassLoaderDomain
;
import
org.jboss.classloader.spi.base.BaseClassLoaderPolicy
;
import
org.jboss.classloader.spi.base.BaseClassLoaderSystem
;
import
org.jboss.util.loading.Translator
;
/**
* Reflective wrapper around a JBoss_5.0.x class loader. Used to encapsulate the classloader-specific methods
* (discovered and called through reflection) from the load-time weaver.
*
* @author Ales Justin
*/
public
class
JBoss50ClassLoader
extends
JBoss5ClassLoader
{
private
Method
addTranslator
;
private
ClassLoaderSystem
system
;
public
JBoss50ClassLoader
(
BaseClassLoader
classLoader
)
{
super
(
classLoader
);
}
protected
void
fallbackStrategy
()
throws
Exception
{
try
{
// let's check if we have a patched policy, with translator per policy
addTranslator
=
getMethod
(
BaseClassLoaderPolicy
.
class
,
"addTranslator"
);
}
catch
(
Exception
ignored
)
{
//log.info("Policy doesn't have addTranslator, falling back to ClassLoaderSystem.");
Method
getClassLoaderDomain
=
getMethod
(
BaseClassLoaderPolicy
.
class
,
"getClassLoaderDomain"
);
BaseClassLoaderDomain
domain
=
invokeMethod
(
getClassLoaderDomain
,
getPolicy
(),
BaseClassLoaderDomain
.
class
);
Method
getClassLoaderSystem
=
getMethod
(
BaseClassLoaderDomain
.
class
,
"getClassLoaderSystem"
);
BaseClassLoaderSystem
system
=
invokeMethod
(
getClassLoaderSystem
,
domain
,
BaseClassLoaderSystem
.
class
);
if
(
system
instanceof
ClassLoaderSystem
)
{
this
.
system
=
ClassLoaderSystem
.
class
.
cast
(
system
);
}
else
{
throw
new
IllegalArgumentException
(
"ClassLoaderSystem must be instance of ["
+
ClassLoaderSystem
.
class
.
getName
()
+
"]"
);
}
}
}
protected
void
addTranslator
(
Translator
translator
)
{
if
(
addTranslator
!=
null
)
{
try
{
addTranslator
.
invoke
(
translator
);
}
catch
(
Exception
e
)
{
throw
new
IllegalArgumentException
(
e
);
}
}
else
{
system
.
setTranslator
(
translator
);
}
}
}
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss51ClassLoader.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
org.jboss.classloader.spi.base.BaseClassLoader
;
import
org.jboss.util.loading.Translator
;
/**
* Reflective wrapper around a JBoss_5.1.x class loader. Used to encapsulate the classloader-specific methods
* (discovered and called through reflection) from the load-time weaver.
*
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
*/
public
class
JBoss51ClassLoader
extends
JBoss5ClassLoader
{
public
JBoss51ClassLoader
(
BaseClassLoader
classLoader
)
{
super
(
classLoader
);
}
protected
void
addTranslator
(
Translator
translator
)
{
getPolicy
().
addTranslator
(
translator
);
}
}
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5ClassLoader.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
java.lang.instrument.ClassFileTransformer
;
import
java.lang.reflect.Method
;
import
java.security.AccessController
;
import
java.security.PrivilegedExceptionAction
;
import
org.jboss.classloader.spi.ClassLoaderPolicy
;
import
org.jboss.classloader.spi.base.BaseClassLoader
;
import
org.jboss.util.loading.Translator
;
import
org.springframework.util.Assert
;
import
org.springframework.instrument.classloading.SimpleThrowawayClassLoader
;
/**
* Reflective wrapper around a JBoss5 class loader. Used to encapsulate the classloader-specific methods (discovered and
* called through reflection) from the load-time weaver.
*
* @author Ales Justin
* @author Marius Bogoevici
*/
public
abstract
class
JBoss5ClassLoader
extends
ReflectionHelper
{
private
final
BaseClassLoader
classLoader
;
private
ClassLoaderPolicy
policy
;
@SuppressWarnings
(
"unchecked"
)
protected
JBoss5ClassLoader
(
BaseClassLoader
classLoader
)
{
Assert
.
notNull
(
classLoader
,
"ClassLoader must not be null"
);
this
.
classLoader
=
classLoader
;
try
{
SecurityManager
sm
=
System
.
getSecurityManager
();
if
(
sm
!=
null
)
{
AccessController
.
doPrivileged
(
new
InstantiationAction
());
}
else
{
doInstantiate
();
}
}
catch
(
Exception
e
)
{
throw
new
IllegalStateException
(
"Could not initialize JBoss ClassLoader because JBoss5 API classes are not available"
,
e
);
}
}
/**
* Get the policy.
*
* @return the policy
*/
protected
ClassLoaderPolicy
getPolicy
()
{
return
policy
;
}
/**
* Do instantiate method, variables.
*
* @throws Exception for any error
*/
private
void
doInstantiate
()
throws
Exception
{
Method
getPolicy
=
getMethod
(
BaseClassLoader
.
class
,
"getPolicy"
);
policy
=
invokeMethod
(
getPolicy
,
classLoader
,
ClassLoaderPolicy
.
class
);
fallbackStrategy
();
}
/**
* The fallback strategy.
*
* @throws Exception for any error
*/
protected
void
fallbackStrategy
()
throws
Exception
{
}
public
void
addTransformer
(
ClassFileTransformer
transformer
)
{
Assert
.
notNull
(
transformer
,
"ClassFileTransformer must not be null"
);
Translator
translator
=
new
ClassFileTransformer2Translator
(
transformer
);
addTranslator
(
translator
);
}
/**
* Add the translator.
*
* @param translator the translator
*/
protected
abstract
void
addTranslator
(
Translator
translator
);
public
ClassLoader
getInternalClassLoader
()
{
return
classLoader
;
}
public
ClassLoader
getThrowawayClassLoader
()
{
return
new
SimpleThrowawayClassLoader
(
classLoader
);
}
/** Instantiation action. */
private
class
InstantiationAction
implements
PrivilegedExceptionAction
{
public
Object
run
()
throws
Exception
{
doInstantiate
();
return
null
;
}
}
}
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
java.lang.instrument.ClassFileTransformer
;
import
java.lang.reflect.Method
;
import
org.jboss.classloader.spi.base.BaseClassLoader
;
import
org.springframework.instrument.classloading.LoadTimeWeaver
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
/**
* {@link LoadTimeWeaver} implementation for JBoss5's instrumentable ClassLoader.
*
* @author Ales Justin
*/
public
class
JBoss5LoadTimeWeaver
extends
ReflectionHelper
implements
LoadTimeWeaver
{
private
JBoss5ClassLoader
classLoader
;
public
JBoss5LoadTimeWeaver
()
{
this
(
ClassUtils
.
getDefaultClassLoader
());
}
public
JBoss5LoadTimeWeaver
(
ClassLoader
classLoader
)
{
Assert
.
notNull
(
classLoader
,
"ClassLoader must not be null"
);
BaseClassLoader
bcl
=
determineClassLoader
(
classLoader
);
if
(
bcl
==
null
)
{
throw
new
IllegalArgumentException
(
classLoader
+
" and its parents are not suitable ClassLoaders: "
+
"An ["
+
BaseClassLoader
.
class
.
getName
()
+
"] implementation is required."
);
}
this
.
classLoader
=
createClassLoaderWrapper
(
bcl
);
}
/**
* Create a JBoss5 classloader wrapper based on the underlying JBossAS version.
*
* @param bcl the base classloader
* @return new JBoss5 classloader wrapper
*/
protected
JBoss5ClassLoader
createClassLoaderWrapper
(
BaseClassLoader
bcl
)
{
int
versionNumber
=
0
;
String
tag
;
try
{
// BCL should see Version class
Class
<?>
versionClass
=
bcl
.
loadClass
(
"org.jboss.Version"
);
Method
getInstance
=
getMethod
(
versionClass
,
"getInstance"
);
Object
version
=
getInstance
.
invoke
(
null
);
// static method
Method
getMajor
=
getMethod
(
versionClass
,
"getMajor"
);
versionNumber
+=
100
*
invokeMethod
(
getMajor
,
version
,
Integer
.
class
);
Method
getMinor
=
getMethod
(
versionClass
,
"getMinor"
);
versionNumber
+=
10
*
invokeMethod
(
getMinor
,
version
,
Integer
.
class
);
Method
getRevision
=
getMethod
(
versionClass
,
"getRevision"
);
versionNumber
+=
invokeMethod
(
getRevision
,
version
,
Integer
.
class
);
Method
getTag
=
getMethod
(
versionClass
,
"getTag"
);
tag
=
invokeMethod
(
getTag
,
version
,
String
.
class
);
}
catch
(
Exception
e
)
{
//log.warn("Exception creating JBoss5 CL wrapper: " + e + ", falling back to JBoss50ClassLoader wrapper.");
return
new
JBoss50ClassLoader
(
bcl
);
}
if
(
versionNumber
<
500
)
// this only works on new MC code
{
throw
new
IllegalArgumentException
(
"JBoss5LoadTimeWeaver can only be used on new JBoss Microcontainer ClassLoader."
);
}
else
if
(
versionNumber
<=
501
||
(
versionNumber
==
510
&&
"Beta1"
.
equals
(
tag
)))
{
return
new
JBoss50ClassLoader
(
bcl
);
}
else
{
return
new
JBoss51ClassLoader
(
bcl
);
}
}
/**
* Find first BaseClassLoader implementation.
*
* @param classLoader the classloader
* @return BaseClassLoader instance or null if not found
*/
private
BaseClassLoader
determineClassLoader
(
ClassLoader
classLoader
)
{
for
(
ClassLoader
cl
=
classLoader
;
cl
!=
null
;
cl
=
cl
.
getParent
())
{
if
(
cl
instanceof
BaseClassLoader
)
{
return
(
BaseClassLoader
)
cl
;
}
}
return
null
;
}
public
void
addTransformer
(
ClassFileTransformer
transformer
)
{
classLoader
.
addTransformer
(
transformer
);
}
public
ClassLoader
getInstrumentableClassLoader
()
{
return
classLoader
.
getInternalClassLoader
();
}
public
ClassLoader
getThrowawayClassLoader
()
{
return
classLoader
.
getThrowawayClassLoader
();
}
}
org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ReflectionHelper.java
0 → 100644
浏览文件 @
471fbf7e
/*
* Copyright 2002-2009 the original author or authors.
*
* 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
org.springframework.instrument.classloading.jboss
;
import
java.lang.reflect.Method
;
/**
* Reflection helper.
*
* @author Ales Justin
*/
public
abstract
class
ReflectionHelper
{
/**
* Get method from class.
*
* @param clazz the owner class
* @param name the method name
* @return declared method
* @throws Exception for any error
*/
protected
static
Method
getMethod
(
Class
<?>
clazz
,
String
name
)
throws
Exception
{
Method
method
=
clazz
.
getDeclaredMethod
(
name
);
method
.
setAccessible
(
true
);
return
method
;
}
/**
* Invoke method and check the result.
*
* @param method the method
* @param target the target
* @param expectedType the expected type
* @param <T> the exact type
* @return invocation's result
* @throws Exception for any error
*/
protected
static
<
T
>
T
invokeMethod
(
Method
method
,
Object
target
,
Class
<
T
>
expectedType
)
throws
Exception
{
Object
result
=
method
.
invoke
(
target
);
if
(
expectedType
.
isInstance
(
result
)
==
false
)
{
throw
new
IllegalArgumentException
(
"Returned result must be instance of ["
+
expectedType
.
getName
()
+
"]"
);
}
return
expectedType
.
cast
(
result
);
}
}
org.springframework.context/template.mf
浏览文件 @
471fbf7e
...
...
@@ -30,6 +30,8 @@ Import-Template:
org.aspectj.weaver.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.codehaus.groovy.*;version="[1.5.0, 2.0.0)";resolution:=optional,
org.joda.*;version="[1.6.0, 2.0.0)";resolution:=optional,
org.jboss.classloader.*;version="[2.0.5, 3.0.0)";resolution:=optional,
org.jboss.util.*;version="[2.2.13, 3.0.0)";resolution:=optional,
org.jruby.*;version="[1.1.0, 2.0.0)";resolution:=optional,
org.omg.CORBA.*;version="0";resolution:=optional,
org.springframework.aop.*;version="[3.0.0, 3.0.1)";resolution:=optional,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录