值得注意的是一下几个类几乎都能通过代码直接写到Bean里面,但是这样的话就固定了BeanInfo,而以下几个类的巧妙之处就在于可以在不改动Bean本身属性的前提下动态的为Bean添加响应的属性。
BeanInfo把一个类看着一个标准Bean。可以获得各个属性的属性形容器来对Bean的属性进行操作。通过Introspector.getBeanInfo(Class<?> beanClass)来实例化
PropertyDescriptor属性形容器,包含着对Bean中属性的相关操作操作。可以通过BeanInfo.getBeanInfo获取或者通过new来实例化.
PropertyChangeListener属性改变监听事件,PropertyChangeSupport绑定Bean和监听器具体操作。通过实现propertyChange方法来自定义自己的操作。通过PropertyChangeSupport的firePropertyChange方法来触发所有监听事件,知道注意的是如果你要在Bean里面封装PropertyChangeSupport通过写方法暴露
监听器的addPropertyChangeListener方法时最好方法名还用addPropertyChangeListener,因为属性描述器的构造方法通过检查Bean里面是否有addPropertyChangeListener方法来判定是否支持绑定属性改变事件(isBound)。
VetoableChangeListener校验监听,有事件监听的使用方法相似,通过VetoableChangeSupport来绑定。通过实现vetoableChange方法来自定义自己的校验。VetoableChangeSupport提供了专门的PropertyVetoException来定义这个校验失败时间应该抛出异常。
实现PropertyEditor接口需要实现12个方法有时间显得过于复杂,可以通过通过继承PropertyEditorSupport并重写setValue或者getValue来是来自定义属性编辑器。
具体简单的使用见代码:
package BeanInfo;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
public class ListenerTest {
// 这些都是可以直接在set里面实现的,但是其独特之处在于动态设置,而不是写在set里面一经写成在代码运行过程中无法改变
public static void main(String[] args) {
TestEntity te1 = new TestEntity();
te1.setName("1");
// 为属性变动增加监听事件1
te1.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName() + "-oldVal:" + evt.getOldValue() + " newVal:" + evt.getNewValue());
}
});
// 为属性变动增加监听事件1
te1.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName() + "开始改变");
}
});
// 为属性变动增加验证事件1 一个专门的属性验证异常PropertyVetoException
te1.addVetoableChangeListener(new VetoableChangeListener() {
@Override
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
if ("2".equals(evt.getNewValue())) {
throw new PropertyVetoException(evt.getPropertyName() + " canot is \"2\"", evt);
}
}
});
te1.getPropertyEditorSupport().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// 因为PropertyEditorSupport的触发机制,这里无法获得PropertyName,NewValue和OldValue
System.out.println(evt.getPropertyName() + evt.getNewValue() + evt.getOldValue() + "EDITOR");
}
});
te1.setName("2"); // 触发事件 TestEntity内部有属性编辑器,会自动做转换。
// 属性编辑器像是一个函数,setValue输入参数,getValue就得或者转换后的参数。
// 不过他作为一个类可以绑定到其他类上,通过继承PropertyEditorSupport并重写setValue或getValue方法来定义属于自己的编辑方式,
// 且setValue会触发PropertyEditorSupport的changeEvent,也就是说你可以为它绑定PropertyChangeListener(默认无法获得oldValue好newValue)。
// 来完成一个动静结合编辑器
te1.setName("3");
System.out.println(te1.getName());
BeanInfo BeanInfo; // BeanInfo 把类看做一个Bean
try {
BeanInfo = Introspector.getBeanInfo(TestEntity.class);
PropertyDescriptor pdName = new PropertyDescriptor("name", TestEntity.class); // 构造一个属性描述器
PropertyDescriptor[] pds = BeanInfo.getPropertyDescriptors(); // 获得一个bean的所以属性描述器
System.out.println("isBound()-" + pdName.isBound()); // 是否支持绑定PropertyChangeListener
System.out.println("isConstrained()-" + pdName.isConstrained()); // 是否绑定了VetoableChangeListener
pdName.setPropertyEditorClass(TestPropertyEditorSupport.class); // 为这个属性描述器绑定属性编辑器class
System.out.println("getPropertyEditorClass()-" + pdName.getPropertyEditorClass()); // 这个属性描述器上绑定的属性编辑器的Class
System.out.println("getPropertyType()-" + pdName.getPropertyType()); // 这个属性的类型
PropertyEditor pe = pdName.createPropertyEditor(te1); // 获得这个属性描述器绑定的属性编辑器的实例化对象
pe.setValue("BBB");
System.out.println(pe.getValue()); // 属性编辑器getValue
try {
PropertyEditor pe2 = (PropertyEditor) new PropertyDescriptor("name", TestEntity.class).getPropertyEditorClass().newInstance();// 这里报空指针,说明属性编辑器只是绑定到属性描述器上了,而不是帮到到Bean的Class上了
pe2.setValue("CCC");
System.out.println(pe2.getValue());
} catch (Exception e) {
System.out.println("NO");
}
pdName.setValue("1", "2");
pdName.getWriteMethod().invoke(te1, "4"); // 执行写方法
System.out.println(te1.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
辅助类:
package BeanInfo;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyEditorSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class TestEntity {
private String name;
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
private VetoableChangeSupport vetoableChangeListeners = new VetoableChangeSupport(this);
private PropertyEditorSupport propertyEditorSupport = new TestPropertyEditorSupport(this);
public String getName() {
return name;
}
public void setName(String name) {
listeners.firePropertyChange("name", this.name, name);
try {
vetoableChangeListeners.fireVetoableChange("name", this.name, name);
propertyEditorSupport.setValue(name);
this.name = (String) propertyEditorSupport.getValue();
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
public void removeVetoableChangeListener(VetoableChangeListener listener) {
vetoableChangeListeners.removeVetoableChangeListener(listener);
}
public void addVetoableChangeListener(VetoableChangeListener listener) {
vetoableChangeListeners.addVetoableChangeListener(listener);
}
public PropertyEditorSupport getPropertyEditorSupport() {
return propertyEditorSupport;
}
public void setPropertyEditorSupport(PropertyEditorSupport propertyEditorSupport) {
this.propertyEditorSupport = propertyEditorSupport;
}
public PropertyChangeSupport getListeners() {
return listeners;
}
public void setListeners(PropertyChangeSupport listeners) {
this.listeners = listeners;
}
}
package BeanInfo;
import java.beans.PropertyEditorSupport;
public class TestPropertyEditorSupport extends PropertyEditorSupport {
public TestPropertyEditorSupport(Object testEntity) {
super(testEntity);
}
@Override
public void setValue(Object value) {
super.setValue(String.valueOf(value) + "AAA");
}
}
执行结果:
name-oldVal:1AAA newVal:2
name开始改变
java.beans.PropertyVetoException: name canot is "2"
at BeanInfo.ListenerTest$3.vetoableChange(ListenerTest.java:42)
at java.beans.VetoableChangeSupport.fireVetoableChange(VetoableChangeSupport.java:375)
at java.beans.VetoableChangeSupport.fireVetoableChange(VetoableChangeSupport.java:271)
at BeanInfo.TestEntity.setName(TestEntity.java:27)
at BeanInfo.ListenerTest.main(ListenerTest.java:57)
name-oldVal:1AAA newVal:3
name开始改变
nullnullnullEDITOR
3AAA
isBound()-true
isConstrained()-false
getPropertyEditorClass()-class BeanInfo.TestPropertyEditorSupport
getPropertyType()-class java.lang.String
BBBAAA
NO
name-oldVal:3AAA newVal:4
name开始改变
nullnullnullEDITOR
4AAA