Java Beans Properties事件
Person类中的事件
- vetoableChangeSupport.fireVetoableChange(String, Object, Object)
- 勉强属性(Constrained properties)必须在更新前执行
- 校验规则:当名称为纯数字时,阻断更新
- 当 PropertyVetoException 异常发生时
- propertyChangeSupport.firePropertyChange(String, Object, Object)
- 发布属性已经变化事件 - PropertyChangeEvent
- 强迫属性(Bound Properties):当属性变化时,强制更新并且发送通知属性变化通知事件
package com.segmentfault.deep.in.java.beans.properties;
import java.beans.*;
import java.io.Serializable;
import java.util.Date;
public class Person implements Serializable {
private static final long serialVersionUID = -1777979663507030142L;
private Long id;
private String name;
private int age;
private Date updateTime;
private final transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
private final transient VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport(this);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) throws PropertyVetoException {
// 当 name 属性变化时,发送通知
// 勉强属性(Constrained properties):当属性变化不合适时,阻断属性更新,并且通知异常来说明
String propertyName = "name";
String oldValue = this.name; // 读取老值
String newValue = name; // 修改后值(newValue)
// 勉强属性(Constrained properties)必须在更新前执行
// 校验规则:当名称为纯数字时,阻断更新
// 当 PropertyVetoException 异常发生时
fireVetoableChange(propertyName, oldValue, newValue);
this.name = name; // this.name
// 发布属性已经变化事件 - PropertyChangeEvent
// 强迫属性(Bound Properties):当属性变化时,强制更新并且发送通知属性变化通知事件
firePropertyChange(propertyName, oldValue, newValue);
}
private void firePropertyChange(String propertyName, String oldValue, String newValue) {
// PropertyChangeEvent event = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
// 广播事件
// 得到所有 PropertyChangeEvent 监听器
propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
public void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException {
vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
public PropertyChangeListener[] getPropertyChangeListeners() {
return propertyChangeSupport.getPropertyChangeListeners();
}
public void addVetoableChangeListener(VetoableChangeListener listener) {
vetoableChangeSupport.addVetoableChangeListener(listener);
}
public void removeVetoableChangeListener(VetoableChangeListener listener) {
vetoableChangeSupport.removeVetoableChangeListener(listener);
}
public VetoableChangeListener[] getVetoableChangeListeners() {
return vetoableChangeSupport.getVetoableChangeListeners();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
// 勉强属性(Constrained properties)必须在更新前执行
// 强迫属性(Bound Properties):当属性变化时,强制更新并且发送通知属性变化通知事件
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", updateTime=" + updateTime +
'}';
}
public static boolean isNumeric(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isDigit(str.charAt(i)) == false) {
return false;
}
}
return true;
}
}
package com.segmentfault.deep.in.java.beans.properties;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static com.segmentfault.deep.in.java.beans.properties.Person.isNumeric;
import static java.lang.String.format;
import static java.lang.String.valueOf;
public class PersonDemo {
public static void main(String[] args) throws PropertyVetoException, ExecutionException, InterruptedException {
Person person = new Person();
// 添加 PropertyChangeListener
person.addPropertyChangeListener(event -> {
// 属性变化通知事件
System.out.printf("监听到属性[%s] 内容变化(事件来源:%s),老值:%s,新值:%s\n",
event.getPropertyName(),
event.getSource(),
event.getOldValue(),
event.getNewValue()
);
});
// 添加 PropertyVetoListener
person.addVetoableChangeListener(event -> {
String newValue = valueOf(event.getNewValue());
if (isNumeric(newValue)) {
throw new PropertyVetoException(
format("当前属性[%s]的新值[%s]不合法,不能为纯数字!", event.getPropertyName(), newValue), event);
}
});
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
e.printStackTrace();
});
// 修改名称 null -> "XIAOMAGE"
person.setName("XIAOMAGE");
System.out.println("当前 person.name = " + person.getName());
// 修改名称 "XIAOMAGE" -> "mercyblitz"
person.setName("mercyblitz");
System.out.println("当前 person.name = " + person.getName());
// 修改名称为 "mercyblitz" -> "12345"
person.setName("12345");
System.out.println("当前 person.name = " + person.getName());
}
}
Java Beans Properties 自定义事件
package com.segmentfault.deep.in.java.beans.customization;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
import static com.segmentfault.deep.in.java.beans.properties.Person.isNumeric;
/**
* Person id 属性编辑器
* Id String -> Long
*/
public class IdPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) {
if (isNumeric(text)) {
setValue(Long.valueOf(text));
}
}
/**
* 覆盖父类方法
*
* @return
*/
@Override
public Long getValue() {
return (Long) super.getValue();
}
}
package com.segmentfault.deep.in.java.beans.customization;
import com.segmentfault.deep.in.java.beans.properties.Person;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyEditor;
import java.util.Date;
import java.util.stream.Stream;
public class PersonBeanCustomization {
public static void main(String[] args) throws IntrospectionException {
// 排除 java.lang.Object.class 类定义的干扰
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);
Person personBean = new Person();
Stream.of(beanInfo.getPropertyDescriptors())
.filter(propertyDescriptor -> "id".equals(propertyDescriptor.getName())) // 过滤 "id" 属性
.findFirst()
.ifPresent(idPropertyDescriptor -> {
// 为 "id" 属性描述注册属性修改器
idPropertyDescriptor.setPropertyEditorClass(IdPropertyEditor.class);
PropertyEditor propertyEditor = idPropertyDescriptor.createPropertyEditor(personBean);
// 添加属性变化事件
propertyEditor.addPropertyChangeListener(event -> {
personBean.setId((Long) propertyEditor.getValue());
});
// 通过 setAsText(String) 方法模拟 <property name="id">1</property>
propertyEditor.setAsText("1");
}
);
Stream.of(beanInfo.getPropertyDescriptors())
.filter(propertyDescriptor -> "updateTime".equals(propertyDescriptor.getName())) // 过滤 "updateTime" 属性
.findFirst()
.ifPresent(propertyDescriptor -> {
// 为 "updateTime" 属性描述注册属性修改器
propertyDescriptor.setPropertyEditorClass(UpdateTimePropertyEditor.class);
PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(personBean);
// 添加属性变化事件
propertyEditor.addPropertyChangeListener(event -> {
personBean.setUpdateTime((Date) propertyEditor.getValue());
});
// 通过 setAsText(String) 方法模拟 <property name="updateTime">2019-10-23 23:16:00</property>
propertyEditor.setAsText("2019-10-23 23:16:00");
}
);
System.out.println("当前 person = " + personBean);
}
}
Java Beans 事件实现
事件类
package com.segmentfault.deep.in.java.beans.event;
import java.util.EventObject;
public class ApplicationEvent extends EventObject {
private final long timestamp;
/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
@Override
public String toString() {
return "ApplicationEvent{" +
"timestamp=" + timestamp +
", source=" + source +
'}';
}
}
监听类
package com.segmentfault.deep.in.java.beans.event;
import java.util.EventListener;
/**
* 应用事件监听器
*
* @see EventListener
* @param <E> ApplicationEvent 以及它的子类型
*/
public interface ApplicationEventListener<E extends ApplicationEvent> extends EventListener {
/**
* 处理事件
* @param event
*/
void onEvent(E event);
}
注册器
package com.segmentfault.deep.in.java.beans.event;
public interface ApplicationEventListenerRegistry {
void addApplicationEventListener(ApplicationEventListener<?> listener);
void removeApplicationEventListener(ApplicationEventListener<?> listener);
ApplicationEventListener[] getApplicationEventListeners();
ApplicationEventListener[] getApplicationEventListeners(Class<? extends ApplicationEvent> eventType);
}
package com.segmentfault.deep.in.java.beans.event;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Stream;
import static java.util.Collections.emptyList;
/**
* 支持泛型 {@link ApplicationEventListener 应用事件监听器}注册中心
*/
public class GenericApplicationEventListenerRegistry implements ApplicationEventListenerRegistry {
/**
* Key 是监听器的类型名称,Value 是多个相同类型的监听器
*/
private Map<String, List<ApplicationEventListener<?>>> typedListeners
= new LinkedHashMap<>();
public void addApplicationEventListener(ApplicationEventListener<?> listener) {
List<ApplicationEventListener<?>> listeners = getListeners(listener);
listeners.add(listener);
}
protected List<ApplicationEventListener<?>> getListeners(ApplicationEventListener<?> listener) {
Class<?> listenerClass = listener.getClass();
Type[] genericInterfaces = listenerClass.getGenericInterfaces();
String eventTypeName = Stream.of(genericInterfaces)
.filter(t -> t instanceof ParameterizedType)// 判断接口是否 ParameterizedType 类型
.map(t -> (ParameterizedType) t) // 转换为 ParameterizedType
// 判断 ApplicationEventListener 原始类型是否
.filter(parameterizedType -> ApplicationEventListener.class.equals(parameterizedType.getRawType()))
.map(parameterizedType -> {
// 获取第一个泛型参数
return parameterizedType.getActualTypeArguments()[0].getTypeName();
})
.findFirst()
.orElse(null);
return typedListeners.computeIfAbsent(eventTypeName, k -> new LinkedList<>());
}
public void removeApplicationEventListener(ApplicationEventListener<?> listener) {
List<ApplicationEventListener<?>> listeners = getListeners(listener);
listeners.remove(listener);
}
/**
* @return 只读的 {@link ApplicationEventListener} 列表
*/
public ApplicationEventListener[] getApplicationEventListeners() {
return new ApplicationEventListener[0];
}
@Override
public ApplicationEventListener[] getApplicationEventListeners(Class<? extends ApplicationEvent> eventType) {
String eventTypeName = eventType.getTypeName();
return typedListeners.getOrDefault(eventTypeName, emptyList()).toArray(new ApplicationEventListener[0]);
}
/**
* 通过 {@link ApplicationEventListener} 实现类去重
*/
static class ApplicationEventListenerComparator implements Comparator<ApplicationEventListener> {
@Override
public int compare(ApplicationEventListener o1, ApplicationEventListener o2) {
String oneClassName = o1.getClass().getName();
String anotherClassName = o2.getClass().getName();
return oneClassName.compareTo(anotherClassName);
}
}
}
package com.segmentfault.deep.in.java.beans.event;
import java.util.*;
/**
* 简单 {@link ApplicationEventListener 应用事件监听器}注册中心实现
*/
public class SimpleApplicationEventListenerRegistry implements ApplicationEventListenerRegistry {
private Set<ApplicationEventListener<?>> listeners = new TreeSet<>(new ApplicationEventListenerComparator());
@Override
public void addApplicationEventListener(ApplicationEventListener<?> listener) {
listeners.add(listener);
}
@Override
public void removeApplicationEventListener(ApplicationEventListener<?> listener) {
listeners.remove(listener);
}
/**
* @return 只读的 {@link ApplicationEventListener} 列表
*/
@Override
public ApplicationEventListener[] getApplicationEventListeners() {
return listeners.toArray(new ApplicationEventListener[0]);
}
@Override
public ApplicationEventListener[] getApplicationEventListeners(Class<? extends ApplicationEvent> eventType) {
return new ApplicationEventListener[0];
}
/**
* 通过 {@link ApplicationEventListener} 实现类去重
*/
static class ApplicationEventListenerComparator implements Comparator<ApplicationEventListener> {
@Override
public int compare(ApplicationEventListener o1, ApplicationEventListener o2) {
String oneClassName = o1.getClass().getName();
String anotherClassName = o2.getClass().getName();
return oneClassName.compareTo(anotherClassName);
}
}
}
事件发布
package com.segmentfault.deep.in.java.beans.event;
/**
* {@link ApplicationEvent} 广播器
*/
public class ApplicationEventMulticaster {
private final ApplicationEventListenerRegistry registry;
public ApplicationEventMulticaster() {
this.registry = new SimpleApplicationEventListenerRegistry();
}
public ApplicationEventMulticaster(ApplicationEventListenerRegistry registry) {
this.registry = registry;
}
public void addApplicationEventListener(ApplicationEventListener<?> listener) {
registry.addApplicationEventListener(listener);
}
public void removeApplicationEventListener(ApplicationEventListener<?> listener) {
registry.removeApplicationEventListener(listener);
}
public ApplicationEventListener[] getApplicationEventListeners() {
return registry.getApplicationEventListeners();
}
public ApplicationEventListener[] getApplicationEventListeners(Class<? extends ApplicationEvent> eventType) {
return registry.getApplicationEventListeners(eventType);
}
public void multicastEvent(ApplicationEvent event) {
// 逐一传递
Class<? extends ApplicationEvent> eventType = event.getClass();
for (ApplicationEventListener listener : getApplicationEventListeners(eventType)) {
listener.onEvent(event);
}
}
public static void main(String[] args) {
// displaySimpleEvent();
displayGenericEvent();
}
private static void displayGenericEvent() {
ApplicationEventMulticaster multicaster =
new ApplicationEventMulticaster(new GenericApplicationEventListenerRegistry());
multicaster.addApplicationEventListener(new MyEventListener());
multicaster.addApplicationEventListener(new MyEventListener2());
// 传播的是 ApplicationEvent,MyEventListener 需要 MyEvent 类型,属于前者子类
multicaster.multicastEvent(new MyEvent("2019"));
}
private static void displaySimpleEvent() {
ApplicationEventMulticaster multicaster = new ApplicationEventMulticaster();
// 注册一个事件监听器
multicaster.addApplicationEventListener(event -> {
System.out.println("处理事件-1 : " + event);
});
multicaster.addApplicationEventListener(event -> {
System.out.println("处理事件-2 : " + event);
});
multicaster.addApplicationEventListener(event -> {
System.out.println("处理事件-3 : " + event);
});
// 广播事件
multicaster.multicastEvent(new ApplicationEvent("Hello,World"));
}
}