Java Beans自定义事件

Java Beans

Posted by 王明高 on November 17, 2019

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"));
    }

}