JavaBeans 是 Sun 1996 年制定的**可重用軟體組件規範**。它不發明新語法,而是約定一組命名模式與行為契約,讓建構工具 (IDE、可視化設計器、腳本引擎) 能**自動發現、操作、連線**組件。核心三要素:
EventListener 模式的通知機制。本文聚焦**屬性分類與設計模式**,這是 JavaBeans 最基礎、應用最廣的部分 (JSP `
單一值,對應一對存取器:
public class SimpleBean {
private String name; // 私有欄位
// 讀取器 (Getter)
public String getName() {
return name;
}
// 寫入器 (Setter)
public void setName(String name) {
this.name = name;
}
}
布林屬性特例:Getter 可命名為 isXxx() (如 isActive()),Setter 仍為 setXxx()。Introspector 會優先識別 is 前綴。
代表有序集合,提供**單元素**與**整體陣列**兩組存取器:
public class IndexedBean {
private String[] items = new String[10];
// 整體陣列存取
public String[] getItems() { return items; }
public void setItems(String[] items) { this.items = items; }
// 單元素存取 (關鍵:參數含索引)
public String getItems(int index) { return items[index]; }
public void setItems(int index, String value) { items[index] = value; }
}
現代替代:優先使用 List<E> + getItems() 返回不可變視圖,或提供 addItem(E)/removeItem(int) 方法,避免直接暴露可變陣列/集合。
屬性值改變時,**自動發送 PropertyChangeEvent 給註冊監聽器**。這是 MVC、資料綁定、表單驗證、響應式 UI 的基石。
import java.beans.*;
public class BoundBean {
private String status = "IDLE";
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public String getStatus() { return status; }
public void setStatus(String status) {
String old = this.status;
this.status = status;
// 發送變更事件:屬性名、舊值、新值
pcs.firePropertyChange("status", old, status);
}
// 標準監聽器管理方法 (供工具識別)
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
}
應用場景:Swing JTable 模型更新、Spring `
擴展綁定屬性:發送 VetoableChangeListener,監聽器可拋出 PropertyVetoException **否決變更**,屬性值保持不變。
import java.beans.*;
public class ConstrainedBean {
private int maxConnections = 100;
private final VetoableChangeSupport vcs = new VetoableChangeSupport(this);
public int getMaxConnections() { return maxConnections; }
public void setMaxConnections(int max) throws PropertyVetoException {
// 發送否決事件,若有監聽器拋出 PropertyVetoException,則中止設定
vcs.fireVetoableChange("maxConnections", maxConnections, max);
this.maxConnections = max; // 只有無異常時才真正修改
}
public void addVetoableChangeListener(VetoableChangeListener listener) {
vcs.addVetoableChangeListener(listener);
}
public void removeVetoableChangeListener(VetoableChangeListener listener) {
vcs.removeVetoableChangeListener(listener);
}
}
使用者代碼:
bean.addVetoableChangeListener(evt -> {
if ("maxConnections".equals(evt.getPropertyName()) && (Integer)evt.getNewValue() > 1000) {
throw new PropertyVetoException("Max connections cannot exceed 1000", evt);
}
});
| 類別 | 用途 |
|---|---|
Introspector | 核心反射引擎:BeanInfo getBeanInfo(Class<?> beanClass) 分析類別結構,提取屬性/事件/方法描述符。 |
PropertyDescriptor | 屬性元資料:名稱、類型、讀/寫方法、是否綁定/受限、屬性編輯器類別。 |
PropertyEditor | 屬性編輯器介面:setAsText(String)/getAsText() 字串↔物件轉換,供建構工具屬性表使用。 |
BeanInfo | 顯式描述 Bean 特性 (可選):**BeanNameBeanInfo** 類別命名慣例可覆蓋預設內省結果,隱藏屬性、指定圖示、自定義屬性編輯器。 |
PropertyChangeSupport / VetoableChangeSupport | 綁定/受限屬性的監聽器管理與事件分發助手 (觀察者模式實作)。 |
withXxx() 返回新實例 (如 Record、Immutable 模式),減少 Setter 暴露。Serializable,宣告 serialVersionUID,transient 標記非持久欄位 (如 PropertyChangeSupport 不可序列化)。Collections.unmodifiableList) 或防禦性複製。public record User(String name, int age) {} — 編譯器自動生成 getName()/age()、equals/hashCode/toString、構造函式,**天然符合 JavaBeans 唯讀屬性模式** (無 Setter)。@Data/@Getter/@Setter/@Builder 編譯期生成樣板代碼,但需注意綁定屬性需手寫 PropertyChangeSupport。@NotNull, @Size, @Max 等註解聲明約束,配合 Validator 實現聲明式驗證,替代受限屬性部分場景。JavaBeans 看似老舊,實則是 **Java 生態互操作的通用語言**。掌握四大屬性模式、PropertyChangeSupport 事件機制、Introspector 內省原理,能讓你在 Spring 配置綁定、JSF/Thymeleaf 表單處理、可視化設計器整合、配置中心熱更新等場景中得心應手。**組件化思維:封裝變化、暴露標準契約、工具友善**,永不過時。