bytebuddy
- 導讀
- 一. 類型描述(description)
- 1.1 設計模式
- 1.2 modifier 修飾符
- 1.2.1 ModifierContributor 修飾符的核心類
- 1.2.1.1 自定義一個 ModifierContributor
- 1.2.1.2 內置的ModifierContributor接口
- 1.2.1.3 內置的ModifierContributor.Resolver類
- 1.2.1.4 其他實現 ModifierContributor的接口
- 1.2.2 ModifierReviewable 修飾符的工廠
- 1.3 共同的接口
- 1.4 Type - class的類型
bytebuddy入門
這個入門其實寫的不好,是筆記性質,給我自己看的。但是可取的
- 是花了一張圖,羅列了bytebuddy的源碼結構和各種類的作用。讓使用bytebuddyAPI中 對各種參數類型作用感到困惑的人有幫助
- 羅列了我所看到的資料:官網的介紹,bytebuddy作者寫這個框架出發點,代碼demo。
- 從我個人來看,bytebuddy並不是針對java開發新手寫的文檔。對類的修改和植入,以及最終如何讓應用到APM產品(比如
skywalking
產品)。
我總結的學習步驟如下
字節碼的知識—>ASM的知識—>JVM一些知識(類的加載,運行,卸載,類型)—> JNI(調用使用第三方代碼) —> jdk attach的原理 —> jdk.instrument 知識 —> bytebuddy的知識。
這是我個人整理的一些資料
- 字節碼知識
《深入理解字節碼》
- asm指導手冊 & asm入門
- JVM 比較零散,核心是classloader的加載機制,Class類詳解
- JNI 理解機制就可以
- jdk.attach 原理 也是理解就可以了,本身不復雜
- instrument 實踐一下,也不復雜都有demo
導讀
整體的講解是自下而上,一層一層遞進着講的。後面的內容的理解依賴於前面的內容。
一. 類型描述(description)
這裏重點講bytebuddy如何封裝類型的,這個是其他模塊的基石
。
最好具備
字節碼
的知識,以及Class類詳解的知識- 從bytebuddy開發指南瞭解到源碼的組織結構
代碼位置
在模塊byte-buddy-dev/description包是有關類型的描述
Class類詳解中有更詳細的介紹
名稱 | 描述 | 備註 |
---|---|---|
annotation | 註解 | |
enumeration | 枚舉 | |
field | filed成員 | |
method | 方法成員 | |
modifier | 修飾符,本質是一個2byte的int,代表一個方法的的描述。比如 public 對應的是 0X0001 | |
modifier | 修飾符,本質是一個2byte的int,代表一個方法的的描述。比如 public 對應的是 0X0001 | |
type | 類型,類型的類型。對Class進行分類 |
1.1 設計模式
bytebuddy的代碼比較整齊,所有的類基本都是如下的模式。
package bytecode.annotation;
public interface ByteBuddyTemplate {
// 接口層
public void method();
// 抽象層
public abstract class AbstractBase implements ByteBuddyTemplate {
public void method() {
System.out.println("base");
}
}
// 實現層
public static class sub01 extends AbstractBase{
@Override
public void method() {
super.method();
System.out.println("sub01");
}
}
public static class sub02 extends AbstractBase {
@Override
public void method() {
super.method();
System.out.println("sub02");
}
}
// 實現層- 常用枚舉模式
enum sub03 implements ByteBuddyTemplate{
INSTANCE;
@Override
public void method() {
}
}
}
基本上有三層結構
- 1層 功能定義
- 2層 抽象實現
- 3層 具體實現 & 經常用枚舉
好處是有個清晰的結構,從接口的定義出發,再細緻到具體的實現,都在一個類中實現。缺點是類很臃腫,一個類基本都是1000+或者10000+行。
1.2 modifier 修飾符
class 以及class成員的字節碼都有u2 access_flags
字段,modifier就是代表着access_flags
。
1.2.1 ModifierContributor 修飾符的核心類
修飾符的核心類,內包含幾個實現,複合1.1的設計模式
會講明白,bytebuddy是如何定義修飾符的,耐心看。
核心方法
public interface ModifierContributor {
/**
* 空的mask
*/
int EMPTY_MASK = 0;
/**
* 獲取mask,mask是有效位數
*/
int getMask();
/**
* 獲取屏蔽位
*/
int getRange();
/**
* 這個是否是最初的 modifier
*/
boolean isDefault();
}
示意圖
標準的access_flags只有16bit,但是asm提供了超過16位的標識,這個只對asm有用,asm 寫入字節碼時,會講多餘的忽慮掉。
比如field字段有意義的標識符只有9位(asm中是10位)。使用mask
可以添加沒有的標誌符
這個是field的mask
// Opcodes.ACC_PUBLIC 就是public 0x0001
int MASK = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE
| Opcodes.ACC_DEPRECATED | Opcodes.ACC_ENUM | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC
| Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE;
mask
是規範中有效的位數,range
是額外的屏蔽位。
public int resolve(int modifiers) {
for (T modifierContributor : modifierContributors) {
modifiers = (modifiers & ~modifierContributor.getRange()) | modifierContributor.getMask();
}
return modifiers;
}
- 說明函數傳入一個
modifier
- 先進行
~modifierContributor.getRange()
運算。加入你要屏蔽掉ACC_PUBLIC 0X0001
。那麼取反碼,第一位就變成了0,其餘爲1,結果爲二進制11111111111111111111111111111110
- 第二步
(modifiers & ~modifierContributor.getRange())
,public的位置就變成了0。 - 最後纔是或
|mask
。注意這裏是或,也就是說有一位爲1,就是1。
所以range
的作用是屏蔽位
1.2.1.1 自定義一個 ModifierContributor
示例
下面是自定義的一個ModifierContributor
實現。DemoModifierContributor.Resolver. resolve(int modifier))
是根據ModifierContributor
對傳入的modifier做修改。
- 比如 demo 的修飾符
public static
代表着1001
- 先用屏蔽位
range
處理(1001 & ~0001) ,結果是1000
- 在用mask 補充額外的位數 1000|1010 ,結果是
1010
所以rang
代表屏蔽,mask
代表額外的添加
public class DemoModifierContributor implements ModifierContributor {
public static String demo = "hello;";
@Override
public int getMask() {
// 僅有前四位有效的mask 即 0000000000001010
int MASK = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
return MASK;
}
@Override
public int getRange() {
// 屏蔽調 public
return Opcodes.ACC_PUBLIC;
}
@Override
public boolean isDefault() {
return false;
}
public static void main(String[] args) throws Exception{
// 打印demo 的modifier
int modifier = DemoModifierContributor.class.getDeclaredField("demo").getModifiers();
System.out.println("origin modifier of demo : "+ Integer.toBinaryString(modifier));
// mask
DemoModifierContributor demo = new DemoModifierContributor();
System.out.println("mask : "+ Integer.toBinaryString(demo.getMask()));
// range
System.out.println("range : "+ Integer.toBinaryString(demo.getRange()));
// resolver 用來獲取 有效的 modifier
List<ModifierContributor> list = Collections.singletonList(new DemoModifierContributor());
DemoModifierContributor.Resolver resolver = DemoModifierContributor.Resolver.of(list);
// 獲取 (modifiers & ~modifierContributor.getRange()) | modifierContributor.getMask();
// (1001 & ~0001)|1100 --> (1001 & 1110)|1010 --> 1000|1010 --> 1010
System.out.println( Integer.toBinaryString(resolver.resolve(modifier)));
}
}
//打印
origin modifier of demo : 1001
mask : 1010
range : 1
1010
1.2.1.2 內置的ModifierContributor接口
內置了四個子接口ForField
,ForMethod
,ForType
,ForParameter
。
通過了解自定義ModifierContributor的子類。就很好理解四個實現,很類似。比如
僅僅是定義了10位mask
interface ForField extends ModifierContributor {
/**
* A mask for all legal modifiers of a Java field.
*/
int MASK = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE
| Opcodes.ACC_DEPRECATED | Opcodes.ACC_ENUM | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC
| Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE;
}
1.2.1.3 內置的ModifierContributor.Resolver類
用來處理int modifiers
。
創建時接受多個ModifierContributor
public static <S extends ModifierContributor> Resolver<S> of(Collection<? extends S> modifierContributors) {
return new Resolver<S>(modifierContributors);
}
使用時,調用resolve獲取處理過的modifiers。
public int resolve(int modifiers) {
for (T modifierContributor : modifierContributors) {
modifiers = (modifiers & ~modifierContributor.getRange()) | modifierContributor.getMask();
}
return modifiers;
}
1.2.1.4 其他實現 ModifierContributor的接口
這個包裏面接口無一例外都是實現ModifierContributor
的類
挑一個說明FieldManifestation
就是來判斷一個Field
是否被final,volatile
或者修飾,
public enum FieldManifestation implements ModifierContributor.ForField {
/**
* Modifier for a non-final, non-volatile field. (This is the default modifier.)
*/
PLAIN(EMPTY_MASK),
/**
* Modifier for a final field.
*/
FINAL(Opcodes.ACC_FINAL),
/**
* Modifier for a volatile field.
*/
VOLATILE(Opcodes.ACC_VOLATILE);
/**
* The mask the modifier contributor.
*/
private final int mask;
/**
* Creates a new field manifestation.
*
* @param mask The modifier mask of this instance.
*/
FieldManifestation(int mask) {
this.mask = mask;
}
/**
* {@inheritDoc}
*/
public int getMask() {
return mask;
}
/**
* {@inheritDoc}
*/
public int getRange() {
return Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE;
}
/**
* {@inheritDoc}
*/
public boolean isDefault() {
return this == PLAIN;
}
/**
* Returns {@code true} if this manifestation represents a {@code final} type.
*
* @return {@code true} if this manifestation represents a {@code final} type.
*/
public boolean isFinal() {
return (mask & Opcodes.ACC_FINAL) != 0;
}
/**
* Returns {@code true} if this manifestation represents a {@code volatile} type.
*
* @return {@code true} if this manifestation represents a {@code volatile} type.
*/
public boolean isVolatile() {
return (mask & Opcodes.ACC_VOLATILE) != 0;
}
/**
* Returns {@code true} if this manifestation represents a field that is neither {@code final} or {@code volatile}.
*
* @return {@code true} if this manifestation represents a field that is neither {@code final} or {@code volatile}.
*/
public boolean isPlain() {
return !isFinal() && !isVolatile();
}
1.2.2 ModifierReviewable 修飾符的工廠
上面講了修飾符的各種實現類,就是一個彙總類,負責統籌上面的修飾符。也是開發中真正被使用的
,一般不會直接使用1.2中的類。
這個類理解起來不復雜,比如 ForFieldDescription
內置了一堆方法來判斷針對field的修飾符。
interface ForFieldDescription extends OfEnumeration {
/**
* Specifies if the modifier described by this object
*/
boolean isVolatile();
/**
*/
boolean isTransient();
/**
*/
FieldManifestation getFieldManifestation();
/**
*/
FieldPersistence getFieldPersistence();
}
實現了ForFieldDescription
的AbstractBase
,看看如何實現isVolatile()
。
可以看出就是 和Opcodes.ACC_VOLATILE 0x0040;
去 &
,看看相應位是否設爲1
abstract class AbstractBase implements ForTypeDefinition, ForFieldDescription, ForMethodDescription, ForParameterDescription {
public boolean isVolatile() {
return matchesMask(Opcodes.ACC_VOLATILE);
}
private boolean matchesMask(int mask) {
return (getModifiers() & mask) == mask;
}
1.3 共同的接口
description 中其他package(除了modifier),都實現了這幾個接口。先講modifier是因爲modifier被這幾個接口使用了。
1.3.1 NamedElement
字節碼的二進制中每個塊都有對應的名稱。NamedElement
就代表了這個結構,方便的獲取塊的名稱。以下是介紹各個函數的作用,以及給了一個實現類 ,查看調用的效果。
public interface NamedElement {
/**
* element 沒有名稱
*/
String NO_NAME = null;
/**
* 源碼中沒有名稱
*/
String EMPTY_NAME = "";
/**
* 源碼中的真實名稱,如果沒有的話,就會返回EMPTY_NAME 。比如`pubclic
* String demo`,demo就是真實名稱
*/
String getActualName();
1.3.1.1 WithRuntimeName、WithOptionalName,WithGenericName、WithDescriptor
在NamedElement中實現NamedElement 的內置接口
名稱 | 接口 | |
---|---|---|
WithRuntimeName | String getName() | 返回對於running Java application可見的字節碼中的名稱 |
java runtime期間,被命名單元的名稱 | getInternalName() | 返回Java class file format中可見的字節碼名稱 |
WithOptionalName | ||
標誌字節碼元素是否被明確命名 | ||
WithGenericName | toGenericString() | 字節碼元素的泛型名稱 |
泛型風格的名稱 | ||
WithDescriptor | getDescriptor() | 返回字節碼元素的描述符 |
返回文件描述符和泛型簽名 | getGenericSignature() | 如果是泛型就返回泛型名稱 |
從一個實現看上面的作用
ForLoadedField
是實現了NamedElement的三個接口
public class NamedElementTest {
public String demo = "one";
public void print() throws Exception {
Field demoField = NamedElementTest.class.getDeclaredField("demo");
FieldDescription.ForLoadedField loadedField = new FieldDescription.ForLoadedField(demoField);
System.out.println("getActualName() : " + loadedField.getActualName());
// 實現了NamedElement中的三個內置實現
System.out.println("impl form WithRuntimeName : " + (loadedField instanceof NamedElement.WithRuntimeName));
System.out.println("getName() : " + loadedField.getName());
System.out.println("getInternalName() : " + loadedField.getInternalName());
System.out.println("impl form WithDescriptor : " + (loadedField instanceof NamedElement.WithDescriptor));
System.out.println("getName() : " + loadedField.getDescriptor());
System.out.println("getGenericSignature() : " + loadedField.getGenericSignature());
System.out.println("impl form WithGenericName : " + (loadedField instanceof NamedElement.WithGenericName));
System.out.println("toGenericString() : " + loadedField.toGenericString());
System.out.println("impl form WithOptionalName : " + (loadedField instanceof NamedElement.WithOptionalName));
}
public static void main(String[] args) throws Exception {
new NamedElementTest().print();
}
}
打印
getActualName() : demo
impl form WithRuntimeName : true
getName() : demo
getInternalName() : demo
impl form WithDescriptor : true
getName() : Ljava/lang/String;
getGenericSignature() : null
impl form WithGenericName : true
toGenericString() : public java.lang.String bytebuddys.NamedElementTest.demo
impl form WithOptionalName : false
1.3.2 DeclaredByType
返回類型的定義,TypeDefinition
後面會講到,這個接口也是最上層的接口之一。
TypeDefinition
是bytebuddy對java 原生Type
的封裝,也是代表了類的類型。
public interface DeclaredByType {
TypeDefinition getDeclaringType();
}
1.3.3 ByteCodeElement
順理成章講到這個類,這個類繼承了上面講到的所有類,除了AnnotationSource
暫時理解爲封裝註解的類,用來處理註解。後面會在介紹註解時會詳細介紹。
ByteCodeElement
從單詞的字面就可以理解,這就代表這一個 字節嗎的一個元素,實現可以是field
,或者method
,等。
核心的方法
名稱 | 接口 | |
---|---|---|
boolean isVisibleTo(TypeDescription typeDescription) | 對於傳入的類型是否可見,比如同級的classLoader加載類,就互相看不見 | |
boolean isAccessibleTo(TypeDescription typeDescription) | 對於傳入的類型是否權限訪問,比如其他類看不見privite |
舉例說明
DemoModifierContributor.class和ByteCodeElementTest.class在同一個包。
ByteCodeElementTest有兩個方法public
和privite
。DemoModifierContributor 可以看見和訪問public
, 但是看不見privite
。
ForLoadedMethod
是ByteCodeElement
的一個實現。下來就來展示看一下。
package bytebuddys;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import java.lang.reflect.Method;
public class ByteCodeElementTest {
private void notSee() {
}
public void canSee() {
}
public void test() throws Exception {
Method notsee = ByteCodeElementTest.class.getDeclaredMethod("notSee");
Method cansee = ByteCodeElementTest.class.getDeclaredMethod("canSee");
MethodDescription.ForLoadedMethod notSeeBD = new MethodDescription.ForLoadedMethod(notsee);
MethodDescription.ForLoadedMethod canSeeBD = new MethodDescription.ForLoadedMethod(cansee);
// 同包下的另外一個類
TypeDescription samePkgAnotherClass = TypeDescription.ForLoadedType.of(DemoModifierContributor.class);
System.out.println("samePkgAnotherClass cant see privite : " + notSeeBD.isVisibleTo(samePkgAnotherClass));
System.out.println("samePkgAnotherClass cant use privite : " + notSeeBD.isAccessibleTo(samePkgAnotherClass));
System.out.println("samePkgAnotherClass can see public : " + canSeeBD.isVisibleTo(samePkgAnotherClass));
System.out.println("samePkgAnotherClass can use public : " + canSeeBD.isAccessibleTo(samePkgAnotherClass));
}
public static void main(String[] args) throws Exception{
new ByteCodeElementTest().test();
}
}
打印
samePkgAnotherClass cant see privite : false
samePkgAnotherClass cant use privite : false
samePkgAnotherClass can see public : true
samePkgAnotherClass can use public : true
1.3.3.1 Token & TypeDependant 類
這兩個類位於ByteCodeElement,但是和ByteCodeElement沒有繼承或者實現關係。
Token
Token,其實就是代表真實的字節碼。熟悉ASM的不會陌生。ASM的CoreAPI接受ClassVister便利class字節碼。Token也是類似的,被用來便利字節碼。
一個Token就是一個字節碼元素。
/**
* A token representing a byte code element.
*
* @param <T> The type of the implementation.
*/
interface Token<T extends Token<T>> {
/**
* Transforms the types represented by this token by applying the given visitor to them.
*
* @param visitor The visitor to transform all types that are represented by this token.
* @return This token with all of its represented types transformed by the supplied visitor.
*/
T accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor);
/**
* A list of tokens.
*
* @param <S> The actual token type.
*/
class TokenList<S extends Token<S>> extends FilterableList.AbstractBase<S, TokenList<S>> {
/**
* The tokens that this list represents.
*/
private final List<? extends S> tokens;
/**
* Creates a list of tokens.
*
* @param token The tokens that this list represents.
*/
@SuppressWarnings("unchecked")
public TokenList(S... token) {
this(Arrays.asList(token));
}
/**
* Creates a list of tokens.
*
* @param tokens The tokens that this list represents.
*/
public TokenList(List<? extends S> tokens) {
this.tokens = tokens;
}
/**
* Transforms all tokens that are represented by this list.
*
* @param visitor The visitor to apply to all tokens.
* @return A list containing the transformed tokens.
*/
public TokenList<S> accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
List<S> tokens = new ArrayList<S>(this.tokens.size());
for (S token : this.tokens) {
tokens.add(token.accept(visitor));
}
return new TokenList<S>(tokens);
}
@Override
protected TokenList<S> wrap(List<S> values) {
return new TokenList<S>(values);
}
/**
* {@inheritDoc}
*/
public S get(int index) {
return tokens.get(index);
}
/**
* {@inheritDoc}
*/
public int size() {
return tokens.size();
}
}
}
- 注意
interface Token<T extends Token<T>>
意味着這個是鏈式的,一個token繼承着上一個token。意味着一個Token,前面有很多限定條件,他必須是誰的子類,這樣你能精確識別Token。 - accept 方法,接受一個visitor,作爲下一個類型的參數。這是訪問者模式。
訪問者模式
Vistitor
我要去拜訪朋友。
我有兩個愛好,喝酒和抽菸。
小李是我的同學,他愛喝酒。當他問我愛什麼,我知道要說喝酒,才能對主人禮貌。
小王是我的同事,他愛抽菸。當他問我愛什麼,我知道要說抽菸,才能對主人禮貌
Host
本地有個待客的習慣,當有客人來時要問,你喜歡什麼。
小李和小王都懂這個禮貌。
除此之外
小李,在詢問前,要先擁抱一下
小王,在詢問前,要握手
…
進一步分析,訪作爲訪問者的我,定義了到訪不同客人家要執行的行爲。
作爲主人的小王和小李,僅僅需要接待我,進行禮貌的詢問。
package bytebuddys;
public class VisitorMode {
// 拜訪者
public interface Visitor {
public void visit(WangHost wangHost);
public void visit(LiHost liHost);
}
public static class MeVisitor implements Visitor {
@Override
public void visit(WangHost wangHost) {
System.out.println(" 抽根菸");
}
@Override
public void visit(LiHost liHost) {
System.out.println(" 來點酒");
}
}
// 主人
public interface Host {
// 接待
public void accept(Visitor v);
// 詢問
default public void ask() {
System.out.println(" 歡迎,你想要點什麼?");
}
}
public static class WangHost implements Host {
public void accept(Visitor v) {
System.out.println("握手");
ask();
v.visit(this);
}
}
public static class LiHost implements Host {
public void accept(Visitor v) {
System.out.println("擁抱");
ask();
v.visit(this);
}
}
public static void main(String[] args) {
System.out.println("風和日麗的一天 我作爲客人");
Visitor me = new MeVisitor();
System.out.println("上午去了小王家,得到了熱情的 款待");
Host wang = new WangHost();
wang.accept(me);
System.out.println("下午去了小李家,得到了熱情的 款待");
Host li = new LiHost();
li.accept(me);
}
}
打印
風和日麗的一天 我作爲客人
上午去了小王家,得到了熱情的 款待
握手
歡迎,你想要點什麼?
抽根菸
下午去了小李家,得到了熱情的 款待
擁抱
歡迎,你想要點什麼?
來點酒
當然Token的更復雜,這個設計可以讓token像金字塔,一層套一層。接受一個類型作爲參數 ,使用accept
,返回下一個token
=當前token
+傳入類型
。
TypeDependant
Dependant —> 受扶養者
一個複合類。充當ElementMatcher
和Token
的橋樑
interface TypeDependant<T extends TypeDependant<?, S>, S extends ByteCodeElement.Token<S>> {
/**
* Returns this type dependant in its defined shape, i.e. the form it is declared in and without its type variable's resolved.
*
* @return This type dependant in its defined shape.
*/
T asDefined();
/**
* Returns a token representative of this type dependant. All types that are matched by the supplied matcher are replaced by
* {@link net.bytebuddy.dynamic.TargetType} descriptions.
*
* @param matcher A matcher to identify types to be replaced by {@link net.bytebuddy.dynamic.TargetType} descriptions.
* @return A token representative of this type dependant.
*/
S asToken(ElementMatcher<? super TypeDescription> matcher);
}
- asDefined() 比如一個類
TypeDependantImpl implments TypeDependant
。
那麼asDefined()就是返回TypeDependantImpl
的作用,就是返回定義的類 - asToken 就是把一個
ElementMatcher
變成Token, ElementMatcher後面會說
1.4 Type - class的類型
1.4.1 TypeVariableSource
首先java中有一個TypeVariable
,這個是泛型中的變量,比如List<T>。這個T就是TypeVariable
。
Byte Buddy 中的TypeVariableSource
和TypeVariable
並不對應。這裏含義更廣:代表了 code element 的類型。
實現了Modifier的接口,具備了判斷access_flags
的能力
繼承下來判斷修飾符的方法
比如
名稱 | 描述 |
---|---|
isPublic() | |
isAbstract() | |
isStatic() |
新添加的方法
isInferrable
名稱 | 描述 |
---|---|
isInferrable() | 類型是否可以被動態的推斷。就是類型可不可義在運行過程中生成,或者更改 |
isGenerified() | 是否是泛型。這個類本身被聲明爲泛型格式class List<T> ,或者內部的類是泛型,那麼都會爲真 |
TypeList.Generic getTypeVariables() | 返回內部的泛型 |
TypeVariableSource getEnclosingSource() | 獲取外部的包裹,Enclosing,Enclosing指的就是類型位於的位置。Enclosed就是內部方法和類型 |
TypeDescription.Generic findVariable(String symbol) | 根據符號,在TypeVariableSource中查找匹配的類型 |
accept(Visitor<T> visitor) | 訪問者模式,visitor中封裝着處理TypeVariableSource 的邏輯。 |
TypeVariableSource UNDEFINED = null; |
不是方法,UNDEFINED 就代表着空的TypeVariableSource |
示例
先重點說一下getEnclosingSource()
,就是獲取外層的包裹類或者方法。
java 自身的getEnclosingMethod()和getEnclosingClass()是一樣的效果。
getEnclosingSource()
相當於兩者之和,這個是在匿名類時特別有用。
public class TypeVariableSourceTest {
public <T extends Food> T makeFood(T food) {
return food;
}
public Object makeSauce() {
class Sauce {
public void print() {
}
}
return new Sauce();
}
// 食物
public static class Food {
}
public static void main(String[] args) throws Exception {
Method makeFood = TypeVariableSourceTest.class.getDeclaredMethod("makeFood", Food.class);
MethodDescription.ForLoadedMethod makeFoodBD = new MethodDescription.ForLoadedMethod(makeFood);
System.out.println("Enclosing 外圍的包裹類" + makeFoodBD.getEnclosingSource().toString());
TypeDescription.ForLoadedType sauceBD = new TypeDescription.ForLoadedType(
new TypeVariableSourceTest().makeSauce().getClass());
System.out.println("Enclosing 外圍的包裹方法" + sauceBD.getEnclosingSource());
}
}
makeFood
方法定義在類內,他的包裹類就是TypeVariableSourceTest
makeSauce
方法產生了一個匿名類,對這個匿名類而言,他的包裹方法就是makeSauce
方法
打印
Enclosing 外圍的包裹類或者方法class bytebuddys.TypeVariableSourceTest
Enclosing 外圍的包裹類public java.lang.Object bytebuddys.TypeVariableSourceTest.makeSauce()
其他方法參照着下面的使用理解
ForLoadedMethod
是一個實現類之一
System.out.println("Inferrce 可否動態修改: " + makeFoodBD.isInferrable());
System.out.println("isGenerified() 是否或者包含泛型: " + makeFoodBD.isGenerified());
System.out.println("Enclosing 外圍的包裹類或者方法: " + makeFoodBD.getEnclosingSource().toString());
System.out.println("getTypeVariables() 獲取泛型: " + makeFoodBD.getTypeVariables().toString());
System.out.println("Enclosing 外圍的包裹類或者方法: " + makeFoodBD.findVariable("T").toString());
打印
Inferrce 可否動態修改: true
isGenerified() 是否或者包含泛型: true
Enclosing 外圍的包裹類或者方法: class bytebuddys.TypeVariableSourceTest
getTypeVariables() 獲取泛型: [T]
Enclosing 外圍的包裹類或者方法: T
1.4.1.1 Vistor
interface Visitor<T> {
/**
* Vistor 針對 typeDescription類型動作
*/
T onType(TypeDescription typeDescription);
/** Vistor 針對 methodDescription類型動作
*/
T onMethod(MethodDescription.InDefinedShape methodDescription);
/** NoOp ,op就是操數,NoOp就是什麼也不幹原樣返回
*/
enum NoOp implements Visitor<TypeVariableSource> {
/**
* The singleton instance.
*/
INSTANCE;
/**
* {@inheritDoc}
*/
public TypeVariableSource onType(TypeDescription typeDescription) {
return typeDescription;
}
/**
* {@inheritDoc}
*/
public TypeVariableSource onMethod(MethodDescription.InDefinedShape methodDescription) {
return methodDescription;
}
}
}
1.4.2 TypeDefinition 類型的定義
就是類型的定義,所有類型的上層接口。提供方便的轉化方法
方法 | 描述 | |
---|---|---|
TypeDescription.Generic asGenericType() | 轉化爲泛型 | |
TypeDescription asErasure() | 擦出類型 | |
TypeDescription.Generic getSuperClass() | 返回父類 | |
TypeList.Generic getInterfaces() | 返回實現的接口類型 | |
FieldList<?> getDeclaredFields() | 返回Fileld類型 | |
MethodList<?> getDeclaredMethods() | 返回method類型 | |
TypeDefinition getComponentType() | 返回數組的類型,比如String[],就返回代表String的類型 | |
RecordComponentList<?> getRecordComponents(); | record是jdk 14新特性,類似C的Struct | |
String getTypeName() | record是jdk 14新特性,類似C的Struct | |
StackSize getStackSize() | 棧幀大小 | |
boolean represents(Type type); | 傳入對象是否相等 | |
Sort getSort() | 返回對象代表的一堆類型,Sort是個集合 |
1.4.2.1 Sort
對象類型的常量的集合
名稱 | 描述 |
---|---|
NON_GENERIC | 非泛型 |
GENERIC_ARRAY | 泛型數組 |
PARAMETERIZED | 參數 |
WILDCARD | WildcardType是Type的子接口,用於描述形如“? extends classA” 或 “?super classB”的“泛型參數表達式”。List<? extends String>這種類型就叫WildcardType |
VARIABLE | 代表了被綁定到net.bytebuddy.description.TypeVariableSource 上的類型 |
VARIABLE_SYMBOLIC | 代表了一個類型,但是僅僅是一個符號,並不會被綁定到net.bytebuddy.description.TypeVariableSource |
public static TypeDescription.Generic describe(Type type)
將一個java中Tpye類型,轉化爲 TypeDescription.Generic 。這個方法很關鍵提供了這樣的轉化。
轉化的實現
protected static TypeDescription.Generic describe(Type type, TypeDescription.Generic.AnnotationReader annotationReader) {
if (type instanceof Class<?>) {
return new TypeDescription.Generic.OfNonGenericType.ForLoadedType((Class<?>) type, annotationReader);
} else if (type instanceof GenericArrayType) {
return new TypeDescription.Generic.OfGenericArray.ForLoadedType((GenericArrayType) type, annotationReader);
} else if (type instanceof ParameterizedType) {
return new TypeDescription.Generic.OfParameterizedType.ForLoadedType((ParameterizedType) type, annotationReader);
} else if (type instanceof TypeVariable) {
return new TypeDescription.Generic.OfTypeVariable.ForLoadedType((TypeVariable<?>) type, annotationReader);
} else if (type instanceof WildcardType) {
return new TypeDescription.Generic.OfWildcardType.ForLoadedType((WildcardType) type, annotationReader);
} else {
throw new IllegalArgumentException("Unknown type: " + type);
}
}