本章解釋如何通過Advice代碼更改函數代碼的方法參數、方法返回和實例變量的值。
這是DataProducer.java的代碼
public class DataProducer{
public static String CLASSNAME = "DataProducer";
public int recordId = 1;
private String descr = "someData";
public int create(int id, String data){
System.out.println("Parameter data:" + id + ", " + data);
System.out.println("Instance variable data:" + recordId + ", " + descr + ", " + CLASSNAME);
if(data != null)
return 1;
else
return -1;
}
}
DataProducer.java
聲明了一個名為create
的函數方法,它接受兩個參數。
create
方法在屏幕上打印其參數值id
、data
以及recordId
、descr
和CLASSNAME
實例變量的值。
之后,該方法根據數據參數的值返回 1
或 -1
的整數值。
當這些程序語句(位于Main1.java中)在沒有Advice代碼的情況下執行時。
public class Main1 {
public static void main(String[] args) {
int dataReceived = new DataProducer().create(10000, "test");
System.out.println("Data returned from create() : " + dataReceived);
}
}
程序在屏幕上生成此結果
Parameter data : 10000, test
Instance variable data : 1, someData, DataProducer
Data returned from create() : 1
現在執行maven構建過程,然后執行Main1.java
,程序在屏幕上生成此結果
Parameter data : 20000, test2
Instance variable data : 2, newData, DataProducer1
Data returned from create() : -2
觀察到屏幕上返回的數據已更改,即使是相同的程序Main1.java:
參數數據:“10000,test”
更改為“20000,test2”
實例變量:“1,someData,DataProducer”
已更改為“2,newData,DataProvider1”
從create
方法返回的數據:“1”
更改為“-2”
.
發生數據更改是因為Advice代碼在檢測過程中截取
了值。
這是DataInterceptor.java的代碼,也是本次中的Advice代碼:
public class DataInterceptor {
@Advice.OnMethodEnter
public static void methodStart(
@Advice.Argument(value=0, readOnly=false) int param1,
@Advice.Argument(value=1, readOnly=false, typing=Assigner.Typing.DYNAMIC) Object param2,
@Advice.FieldValue(value="recordId", readOnly=false) int data1,
@Advice.FieldValue(value="descr", readOnly=false, typing=Assigner.Typing.DYNAMIC) Object data2,
@Advice.FieldValue(value="CLASSNAME", readOnly=false, typing=Assigner.Typing.DYNAMIC) Object data3){
param1 = 20000;
param2 = "test2";
data1 = 2;
data2 = "newData";
data3 = "DataProducer1";
}
@Advice.OnMethodExit
public static void methodEnd(
@Advice.Return(readOnly=false) int returnObject){
returnObject = -2;
}
}
要截取參數、實例變量和返回對象的值,檢測過程必須實現OnMethodEnter
Advice、OnMethodExit
Advice和plugin
程序。
本章將重點解釋Advice
代碼的實現,因為plugin程序與前一章類似。
1、截獲方法參數值
更改DataProducer.java
的create
方法的id
參數的值。
DataInterceptor.java
對param1
參數使用@Argument
注釋
@Advice.Argument(value=0, readOnly=false) int param1
value
屬性使用值0
,這意味著該參數被映射到create
方法的第一個參數
。
注釋為readOnly
屬性指定了false值,這意味著advice方法想要更改create方法的第一個參數的值。
readOnly
屬性的默認值為true
,這將防止Advice代碼更改參數值。
因此,Advice方法可以將第一個參數值從10000更改為20000:
param1 = 20000;
接下來,該注解被配置為更改create方法的第二個參數的值:
@Advice.Argument(value=1, readOnly=false, typing=Assigner.Typing.DYNAMIC) Object param2
value
屬性為1
表示param2
映射到create
方法的第二個參數
。
readOnly
為false
屬性表示數據參數的值是可變的,param2參數映射到數據參數。
第三個屬性type
的值為Assigner.typing.DYNAMIC
。
數據參數是java.lang.String
,Advice方法嘗試使用java.lang.Object
映射param2
參數。
為了使param2
具有java.lang.String
以外的其他數據類型,type
屬性的值必須為DYNAMIC
(動態的),否則,maven構建過程將失敗。
Advice注解的類型屬性默認為static
。
param2
必須具有與其映射參數完全相同的數據類型,
因為param2
想要使用java.lang.Object
,所以DYNAMIC類型
是正確的屬性值。
因此,使用@Argument
注解中的這些配置,Advice代碼可以將param2的值從"test"更改為"test2":
param2 = "test2";
2、攔截實例和類變量
advice方法還更改DataProducer.java
的實例變量
和類變量
的值。
有一個名為CLASSNAME
的類變量和兩個名為recordId
和descr
的實例變量。
要更改實例或類變量的值,請使用@FieldValue
注解而不是@Argument
。
此注解配置為更改recordId
的值:
@Advice.FieldValue(value="recordId", readOnly=false) int data1
要將data1
參數映射到recordId
實例變量,value屬性指定實例變量的名稱"recordId"
。
readOnly
屬性的值為false
,這意味著recordId
變量的值在advice方法中是可變的。
因此,將recordId
變量的值從1
更改為2
data1 = 2;
此注解配置為更改DataProducer.java
中descr
實例變量的值:
@Advice.FieldValue(value=”descr”,readOnly=false,
typing=Assigner.Typing.DYNAMIC) Object data2
該注解希望使用java.lang.Object
數據類型來映射descr
實例變量的數據類型,即java.langString
。
因此,type
屬性必須使用Assigner.typing.DYNAMIC
的值。
通過這些配置,將descr
變量的值從"some data"
更改為"newData"
:
data2 = "newData";
@FieldValue
還可以更改函數代碼的類變量。
為此配置此注釋:
@Advice.FieldValue(value=”CLASSNAME”,readOnly=false,
typing=Assigner.Typing.DYNAMIC) Object data3
通過這些配置,將CLASSNAME
變量的值從"DataProducer"
更改為"DataProvider1"
:
data3 = "DataProducer1";
3、截取方法返回值
除了更改方法參數和實例變量的值之外,Advice代碼還可以更改create方法的返回值
。
為此,@Return
注釋必須用于OnMethodExit
advice方法的參數:
@Advice.OnMethodExit
public static void methodEnd(@Advice.Return(readOnly=false) int returnObject){
returnObject = -2;
}
使用@Return
注釋,methodEnd
方法中returnObject
變量的值更改將反映在create
方法的返回值中
。
利用該配置,將返回值從1
更改為-2
:
returnObject = -2;
結論
本章解釋:
如何更改函數方法的方法參數值
如何更改函數代碼實例變量的值
如何更改函數方法的返回值
bytebuddy書籍《Java Interceptor Development with ByteBuddy: Fundamental》
喜歡就點個??吧