Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
javalover123888
SkyWalking
提交
736c04be
S
SkyWalking
项目概览
javalover123888
/
SkyWalking
与 Fork 源项目一致
Fork自
山不在高_有仙则灵 / SkyWalking
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
SkyWalking
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
736c04be
编写于
12月 20, 2015
作者:
wu-sheng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
1.match方法中,比较是否模糊匹配,判断不准确。
上级
069f1182
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
246 addition
and
205 deletion
+246
-205
skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingEnhanceProcessor.java
...oud/skywalking/plugin/spring/TracingEnhanceProcessor.java
+246
-205
未找到文件。
skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingEnhanceProcessor.java
浏览文件 @
736c04be
package
com.ai.cloud.skywalking.plugin.spring
;
import
com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender
;
import
com.ai.cloud.skywalking.model.Identification
;
import
com.ai.cloud.skywalking.plugin.spring.TracingClassBean
;
import
com.ai.cloud.skywalking.plugin.spring.util.ConcurrentHashSet
;
import
javassist.*
;
import
java.util.Set
;
import
java.util.concurrent.ThreadLocalRandom
;
import
javassist.CannotCompileException
;
import
javassist.ClassPool
;
import
javassist.CtClass
;
import
javassist.CtField
;
import
javassist.CtMethod
;
import
javassist.CtNewMethod
;
import
javassist.NotFoundException
;
import
javassist.bytecode.AnnotationsAttribute
;
import
javassist.bytecode.ConstPool
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.DisposableBean
;
...
...
@@ -16,205 +22,240 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContextAware
;
import
java.util.Set
;
import
java.util.concurrent.ThreadLocalRandom
;
import
com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender
;
import
com.ai.cloud.skywalking.model.Identification
;
import
com.ai.cloud.skywalking.plugin.spring.util.ConcurrentHashSet
;
public
class
TracingEnhanceProcessor
implements
DisposableBean
,
BeanPostProcessor
,
BeanFactoryPostProcessor
,
ApplicationContextAware
{
private
final
Set
<
TracingClassBean
>
beanSet
=
new
ConcurrentHashSet
<
TracingClassBean
>();
private
ApplicationContext
applicationContext
;
@Override
public
void
postProcessBeanFactory
(
ConfigurableListableBeanFactory
beanFactory
)
throws
BeansException
{
applicationContext
.
getBeansOfType
(
TracingClassBean
.
class
);
}
@Override
public
Object
postProcessBeforeInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
return
bean
;
}
private
enum
MatchType
{
METHOD
,
PACKAGE
,
CLASS
;
}
private
boolean
checkMatch
(
String
value
,
String
pattern
,
MatchType
matchType
)
{
boolean
result
;
if
(
"*"
.
equals
(
pattern
))
{
return
true
;
}
if
(
matchType
==
MatchType
.
PACKAGE
)
{
if
(
pattern
.
endsWith
(
".*"
))
{
String
newPattern
=
pattern
.
substring
(
0
,
pattern
.
lastIndexOf
(
".*"
));
result
=
value
.
startsWith
(
newPattern
);
}
else
{
result
=
value
.
equals
(
pattern
);
}
}
else
{
if
(
pattern
.
endsWith
(
"*"
))
{
String
newPattern
=
pattern
.
substring
(
0
,
pattern
.
lastIndexOf
(
"*"
));
result
=
value
.
startsWith
(
newPattern
);
}
else
{
result
=
value
.
equals
(
pattern
);
}
}
return
result
;
}
@Override
public
Object
postProcessAfterInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
String
packageName
=
bean
.
getClass
().
getPackage
().
getName
();
String
className
=
bean
.
getClass
().
getSimpleName
();
TracingClassBean
matchClassBean
=
null
;
boolean
isMatch
=
false
;
for
(
TracingClassBean
tracingClassBean
:
beanSet
)
{
if
(
checkMatch
(
packageName
,
tracingClassBean
.
getPackageName
(),
MatchType
.
PACKAGE
)
||
checkMatch
(
className
,
tracingClassBean
.
getClassName
(),
MatchType
.
CLASS
))
{
isMatch
=
true
;
matchClassBean
=
tracingClassBean
;
continue
;
}
}
if
(!
isMatch
||
matchClassBean
==
null
)
{
return
bean
;
}
// 符合规范
try
{
ClassPool
pool
=
ClassPool
.
getDefault
();
CtClass
ctSource
=
pool
.
get
(
bean
.
getClass
().
getName
());
CtClass
ctDestination
=
pool
.
makeClass
(
generateProxyClassName
(
bean
),
ctSource
);
// 拷贝所有的方法,
copyAllFields
(
ctSource
,
ctDestination
);
// 拷贝所有的注解
copyClassAnnotation
(
ctSource
,
ctDestination
);
// 拷贝所有的方法,并增强
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
for
(
CtMethod
m
:
ctSource
.
getDeclaredMethods
())
{
CtMethod
newm
=
CtNewMethod
.
copy
(
m
,
m
.
getName
(),
ctDestination
,
null
);
copyMethodAnnotation
(
cp
,
m
,
newm
);
// 是否符合规范,符合则增强
if
(
checkMatch
(
m
.
getName
(),
matchClassBean
.
getMethod
(),
MatchType
.
METHOD
))
{
enhanceMethod
(
bean
,
newm
);
}
ctDestination
.
addMethod
(
newm
);
}
Class
generateClass
=
ctDestination
.
toClass
();
Object
newBean
=
generateClass
.
newInstance
();
BeanUtils
.
copyProperties
(
bean
,
newBean
);
return
newBean
;
}
catch
(
NotFoundException
e
)
{
throw
new
IllegalStateException
(
"Class ["
+
beanName
.
getClass
().
getName
()
+
"] cannot be found"
,
e
);
}
catch
(
CannotCompileException
e
)
{
throw
new
IllegalStateException
(
"Class ["
+
beanName
.
getClass
().
getName
()
+
"] cannot be compile"
,
e
);
}
catch
(
InstantiationException
e
)
{
throw
new
IllegalStateException
(
"Failed to instance class["
+
beanName
.
getClass
().
getName
()
+
"]"
,
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
IllegalStateException
(
"Failed to access class["
+
beanName
.
getClass
().
getName
()
+
"]"
,
e
);
}
}
private
void
copyMethodAnnotation
(
ConstPool
cp
,
CtMethod
m
,
CtMethod
newm
)
{
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
m
.
getMethodInfo
()
.
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
m
.
getMethodInfo
()
.
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
newm
.
getMethodInfo
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
newm
.
getMethodInfo
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
private
String
generateProxyClassName
(
Object
bean
)
{
return
bean
.
getClass
().
getName
()
+
"$EnhanceBySWTracing$"
+
ThreadLocalRandom
.
current
().
nextInt
(
100
);
}
private
void
copyAllFields
(
CtClass
ctSource
,
CtClass
ctDestination
)
throws
CannotCompileException
,
NotFoundException
{
// copy fields
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
for
(
CtField
ctSourceField
:
ctSource
.
getDeclaredFields
())
{
CtClass
fieldTypeClass
=
ClassPool
.
getDefault
().
get
(
ctSourceField
.
getType
().
getName
());
CtField
ctField
=
new
CtField
(
fieldTypeClass
,
ctSourceField
.
getName
(),
ctDestination
);
// with annotations
copyAllFieldAnnotation
(
cp
,
ctSourceField
,
ctField
);
ctDestination
.
addField
(
ctField
);
}
}
private
void
copyAllFieldAnnotation
(
ConstPool
cp
,
CtField
ctSourceField
,
CtField
ctDestinationField
)
throws
CannotCompileException
{
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
ctSourceField
.
getFieldInfo
().
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
ctSourceField
.
getFieldInfo
().
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
ctDestinationField
.
getFieldInfo
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
ctDestinationField
.
getFieldInfo
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
private
void
copyClassAnnotation
(
CtClass
ctSource
,
CtClass
ctDestination
)
{
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
ctSource
.
getClassFile
().
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
ctSource
.
getClassFile
().
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
ctDestination
.
getClassFile
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
ctDestination
.
getClassFile
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
protected
void
enhanceMethod
(
Object
bean
,
CtMethod
method
)
throws
CannotCompileException
,
NotFoundException
{
ClassPool
cp
=
method
.
getDeclaringClass
().
getClassPool
();
method
.
addLocalVariable
(
"___sender"
,
cp
.
get
(
LocalBuriedPointSender
.
class
.
getName
()));
method
.
insertBefore
(
"___sender = new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"();___sender.beforeSend"
+
generateBeforeSendParameter
(
bean
,
method
));
method
.
addCatch
(
"new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"().handleException(e);throw e;"
,
ClassPool
.
getDefault
()
.
getCtClass
(
Throwable
.
class
.
getName
()),
"e"
);
method
.
insertAfter
(
"new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"().afterSend();"
,
true
);
}
private
String
generateBeforeSendParameter
(
Object
bean
,
CtMethod
method
)
throws
NotFoundException
{
StringBuilder
builder
=
new
StringBuilder
(
"("
+
Identification
.
class
.
getName
()
+
".newBuilder().viewPoint(\""
+
bean
.
getClass
().
getName
()
+
"."
+
method
.
getName
());
builder
.
append
(
"("
);
for
(
CtClass
param
:
method
.
getParameterTypes
())
{
builder
.
append
(
param
.
getSimpleName
()
+
","
);
}
if
(
method
.
getParameterTypes
().
length
>
0
)
{
builder
=
builder
.
delete
(
builder
.
length
()
-
1
,
builder
.
length
());
}
builder
.
append
(
")"
);
builder
.
append
(
"\").spanType('M').build());"
);
return
builder
.
toString
();
}
private
boolean
isClassNameMatch
(
Object
bean
,
String
tracingClassBean
)
{
//
String
classNamePrefix
=
tracingClassBean
;
if
(
tracingClassBean
.
endsWith
(
"*"
))
{
classNamePrefix
=
tracingClassBean
.
substring
(
0
,
tracingClassBean
.
indexOf
(
'*'
));
}
return
bean
.
getClass
().
getSimpleName
().
startsWith
(
classNamePrefix
);
}
private
boolean
isPackageMatch
(
Object
bean
,
String
packageName
)
{
return
bean
.
getClass
().
getPackage
().
equals
(
packageName
);
}
@Override
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
throws
BeansException
{
this
.
applicationContext
=
applicationContext
;
}
@Override
public
void
destroy
()
throws
Exception
{
public
class
TracingEnhanceProcessor
implements
DisposableBean
,
BeanPostProcessor
,
BeanFactoryPostProcessor
,
ApplicationContextAware
{
private
final
Set
<
TracingClassBean
>
beanSet
=
new
ConcurrentHashSet
<
TracingClassBean
>();
private
ApplicationContext
applicationContext
;
@Override
public
void
postProcessBeanFactory
(
ConfigurableListableBeanFactory
beanFactory
)
throws
BeansException
{
applicationContext
.
getBeansOfType
(
TracingClassBean
.
class
);
//beanSet.addAll(beanFactory.getBeansOfType(TracingClassBean.class).values());
}
@Override
public
Object
postProcessBeforeInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
return
bean
;
}
public
enum
MatchType
{
METHOD
,
PACKAGE
,
CLASS
;
}
private
boolean
checkMatch
(
String
value
,
String
pattern
,
MatchType
matchType
)
{
boolean
result
;
if
(
"*"
.
equals
(
pattern
))
{
return
true
;
}
if
(
matchType
==
MatchType
.
PACKAGE
&&
".*"
.
equals
(
pattern
))
{
String
newPattern
=
pattern
.
substring
(
0
,
pattern
.
lastIndexOf
(
".*"
));
result
=
value
.
startsWith
(
newPattern
);
}
else
{
if
(
"*"
.
equals
(
pattern
)
&&
matchType
!=
MatchType
.
PACKAGE
)
{
String
newPattern
=
pattern
.
substring
(
0
,
pattern
.
lastIndexOf
(
"*"
));
result
=
value
.
startsWith
(
newPattern
);
}
else
{
result
=
value
.
equals
(
pattern
);
}
}
return
result
;
}
@Override
public
Object
postProcessAfterInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
String
packageName
=
bean
.
getClass
().
getPackage
().
getName
();
String
className
=
bean
.
getClass
().
getSimpleName
();
TracingClassBean
matchClassBean
=
null
;
boolean
isMatch
=
false
;
for
(
TracingClassBean
tracingClassBean
:
beanSet
)
{
if
(
checkMatch
(
packageName
,
tracingClassBean
.
getPackageName
(),
MatchType
.
PACKAGE
)
||
checkMatch
(
className
,
tracingClassBean
.
getClassName
(),
MatchType
.
CLASS
))
{
isMatch
=
true
;
matchClassBean
=
tracingClassBean
;
continue
;
}
}
if
(!
isMatch
||
matchClassBean
==
null
)
{
return
bean
;
}
//符合规范
try
{
ClassPool
pool
=
ClassPool
.
getDefault
();
CtClass
ctSource
=
pool
.
get
(
bean
.
getClass
().
getName
());
CtClass
ctDestination
=
pool
.
makeClass
(
generateProxyClassName
(
bean
),
ctSource
);
//拷贝所有的方法,
copyAllFields
(
ctSource
,
ctDestination
);
// 拷贝所有的注解
copyClassAnnotation
(
ctSource
,
ctDestination
);
//拷贝所有的方法,并增强
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
for
(
CtMethod
m
:
ctSource
.
getDeclaredMethods
())
{
CtMethod
newm
=
CtNewMethod
.
copy
(
m
,
m
.
getName
(),
ctDestination
,
null
);
copyMethodAnnotation
(
cp
,
m
,
newm
);
// 是否符合规范,符合则增强
if
(
checkMatch
(
m
.
getName
(),
matchClassBean
.
getMethod
(),
MatchType
.
METHOD
))
{
enhanceMethod
(
bean
,
newm
);
}
ctDestination
.
addMethod
(
newm
);
}
Class
generateClass
=
ctDestination
.
toClass
();
Object
newBean
=
generateClass
.
newInstance
();
BeanUtils
.
copyProperties
(
bean
,
newBean
);
return
newBean
;
}
catch
(
NotFoundException
e
)
{
throw
new
IllegalStateException
(
"Class ["
+
beanName
.
getClass
().
getName
()
+
"] cannot be found"
,
e
);
}
catch
(
CannotCompileException
e
)
{
throw
new
IllegalStateException
(
"Class ["
+
beanName
.
getClass
().
getName
()
+
"] cannot be compile"
,
e
);
}
catch
(
InstantiationException
e
)
{
throw
new
IllegalStateException
(
"Failed to instance class["
+
beanName
.
getClass
().
getName
()
+
"]"
,
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
IllegalStateException
(
"Failed to access class["
+
beanName
.
getClass
().
getName
()
+
"]"
,
e
);
}
}
private
void
copyMethodAnnotation
(
ConstPool
cp
,
CtMethod
m
,
CtMethod
newm
)
{
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
m
.
getMethodInfo
().
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
m
.
getMethodInfo
().
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
newm
.
getMethodInfo
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
newm
.
getMethodInfo
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
private
String
generateProxyClassName
(
Object
bean
)
{
return
bean
.
getClass
().
getName
()
+
"$EnhanceBySWTracing$"
+
ThreadLocalRandom
.
current
().
nextInt
(
100
);
}
private
void
copyAllFields
(
CtClass
ctSource
,
CtClass
ctDestination
)
throws
CannotCompileException
,
NotFoundException
{
// copy fields
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
for
(
CtField
ctSourceField
:
ctSource
.
getDeclaredFields
())
{
CtClass
fieldTypeClass
=
ClassPool
.
getDefault
().
get
(
ctSourceField
.
getType
().
getName
());
CtField
ctField
=
new
CtField
(
fieldTypeClass
,
ctSourceField
.
getName
(),
ctDestination
);
//with annotations
copyAllFieldAnnotation
(
cp
,
ctSourceField
,
ctField
);
ctDestination
.
addField
(
ctField
);
}
}
private
void
copyAllFieldAnnotation
(
ConstPool
cp
,
CtField
ctSourceField
,
CtField
ctDestinationField
)
throws
CannotCompileException
{
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
ctSourceField
.
getFieldInfo
().
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
ctSourceField
.
getFieldInfo
().
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
ctDestinationField
.
getFieldInfo
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
ctDestinationField
.
getFieldInfo
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
private
void
copyClassAnnotation
(
CtClass
ctSource
,
CtClass
ctDestination
)
{
ConstPool
cp
=
ctDestination
.
getClassFile
().
getConstPool
();
AnnotationsAttribute
invAnn
=
(
AnnotationsAttribute
)
ctSource
.
getClassFile
().
getAttribute
(
AnnotationsAttribute
.
invisibleTag
);
AnnotationsAttribute
visAnn
=
(
AnnotationsAttribute
)
ctSource
.
getClassFile
().
getAttribute
(
AnnotationsAttribute
.
visibleTag
);
if
(
invAnn
!=
null
)
{
ctDestination
.
getClassFile
().
addAttribute
(
invAnn
.
copy
(
cp
,
null
));
}
if
(
visAnn
!=
null
)
{
ctDestination
.
getClassFile
().
addAttribute
(
visAnn
.
copy
(
cp
,
null
));
}
}
protected
void
enhanceMethod
(
Object
bean
,
CtMethod
method
)
throws
CannotCompileException
,
NotFoundException
{
ClassPool
cp
=
method
.
getDeclaringClass
().
getClassPool
();
method
.
addLocalVariable
(
"___sender"
,
cp
.
get
(
LocalBuriedPointSender
.
class
.
getName
()));
method
.
insertBefore
(
"___sender = new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"();___sender.beforeSend"
+
generateBeforeSendParameter
(
bean
,
method
));
method
.
addCatch
(
"new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"().handleException(e);throw e;"
,
ClassPool
.
getDefault
().
getCtClass
(
Throwable
.
class
.
getName
()),
"e"
);
method
.
insertAfter
(
"new "
+
LocalBuriedPointSender
.
class
.
getName
()
+
"().afterSend();"
,
true
);
}
private
String
generateBeforeSendParameter
(
Object
bean
,
CtMethod
method
)
throws
NotFoundException
{
StringBuilder
builder
=
new
StringBuilder
(
"("
+
Identification
.
class
.
getName
()
+
".newBuilder().viewPoint(\""
+
bean
.
getClass
().
getName
()
+
"."
+
method
.
getName
());
builder
.
append
(
"("
);
for
(
CtClass
param
:
method
.
getParameterTypes
())
{
builder
.
append
(
param
.
getSimpleName
()
+
","
);
}
if
(
method
.
getParameterTypes
().
length
>
0
)
{
builder
=
builder
.
delete
(
builder
.
length
()
-
1
,
builder
.
length
());
}
builder
.
append
(
")"
);
builder
.
append
(
"\").spanType('M').build());"
);
return
builder
.
toString
();
}
private
boolean
isClassNameMatch
(
Object
bean
,
String
tracingClassBean
)
{
//
String
classNamePrefix
=
tracingClassBean
;
if
(
tracingClassBean
.
endsWith
(
"*"
))
{
classNamePrefix
=
tracingClassBean
.
substring
(
0
,
tracingClassBean
.
indexOf
(
'*'
));
}
return
bean
.
getClass
().
getSimpleName
().
startsWith
(
classNamePrefix
);
}
private
boolean
isPackageMatch
(
Object
bean
,
String
packageName
)
{
return
bean
.
getClass
().
getPackage
().
equals
(
packageName
);
}
@Override
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
throws
BeansException
{
this
.
applicationContext
=
applicationContext
;
}
@Override
public
void
destroy
()
throws
Exception
{
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录