ericchunli 阅读(23) 评论(0)

在实际的项目中支付对账实现大致分为四部分:远程获取相关对账文件,保存相关对账文件到本地,解析对账文件并保存数据,最后进行数据对账。在实现对账的过程中的每条数据都会有对应的初始状态,每完成一个对账步骤都会存在对应的对账状态的修改,此时可以使用PropertyChange*实现对对账状态的监听,每次状态修改时都让其实现自己的业务逻辑。

1.PropertyChange*的简单运用

public class ProBean {

    protected final PropertyChangeSupport support = new PropertyChangeSupport(this);

    private String str="original";

    public String getStr() {

        return str;

    }

    public void setStr(String str) {

        support.firePropertyChange("str", this.str, str);

        this.str = str;

    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {

        support.addPropertyChangeListener(listener);

    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {

        support.removePropertyChangeListener(listener);

    }

}

public class PropertyChangeSupportTest {

    public static void main(String[] args) {

        ProBean proBean = new ProBean();

        proBean.addPropertyChangeListener(new PropertyChangeListenerExp());

        proBean.setStr("change");

    }

    public static class PropertyChangeListenerExp implements PropertyChangeListener {

        @Override

        public void propertyChange(PropertyChangeEvent evt) {

            System.out.println(evt.getPropertyName() + "   " + evt.getNewValue() + "   " + evt.getOldValue());

            // 可以实现自己的业务逻辑

        }

    }

}

输出:【str   change   original】

2.源码分析

每个Bean只要添加PropertyChangeSupport的引用就可以实现属性的绑定。在PropertyChangeSupport的内部维护了一个PropertyChangeListenerMap的对象: private PropertyChangeListenerMap map = new PropertyChangeListenerMap(); 在Support中无论是添加还是移除监听器或者是监听器的代理都是针对map的操作,源码如下:

    public void addPropertyChangeListener(PropertyChangeListener listener) {

        if (listener == null) {

            return;

        }

        if (listener instanceof PropertyChangeListenerProxy) {

            PropertyChangeListenerProxy proxy =

                   (PropertyChangeListenerProxy)listener;

            // Call two argument add method.

            addPropertyChangeListener(proxy.getPropertyName(),

                                      proxy.getListener());

        } else {

            this.map.add(null, listener);

        }

    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {

        if (listener == null) {

            return;

        }

        if (listener instanceof PropertyChangeListenerProxy) {

            PropertyChangeListenerProxy proxy =

                    (PropertyChangeListenerProxy)listener;

            // Call two argument remove method.

            removePropertyChangeListener(proxy.getPropertyName(),

                                         proxy.getListener());

        } else {

            this.map.remove(null, listener);

        }

    }

PropertyChangeListenerMap源码解析:

private static final class PropertyChangeListenerMap extends ChangeListenerMap<PropertyChangeListener> ,故此处针对PropertyChangeListenerMap的监听器的添加与移除其实是在ChangeListenerMap中实现的。ChangeListenerMap是个抽象类,它内部维护了一个Map对象:private Map<String, L[]> map;无论是添加还是移除监听器,都是对map进行处理。

    public final synchronized void add(String name, L listener) {

        if (this.map == null) {

            this.map = new HashMap<String, L[]>();

        }

        L[] array = this.map.get(name);

        int size = (array != null) ? array.length : 0;

        L[] clone = newArray(size + 1);

        clone[size] = listener;

        if (array != null) {

            System.arraycopy(array, 0, clone, 0, size);

        }

        this.map.put(name, clone);

    }

    public final synchronized void remove(String name, L listener) {

        if (this.map != null) {

            L[] array = this.map.get(name);

            if (array != null) {

                for (int i = 0; i < array.length; i++) {

                    if (listener.equals(array[i])) {

                        int size = array.length - 1;

                        if (size > 0) {

                            L[] clone = newArray(size);

                            System.arraycopy(array, 0, clone, 0, i);

                            System.arraycopy(array, i + 1, clone, i, size - i);

                            this.map.put(name, clone);

                        }

                        else {

                            this.map.remove(name);

                            if (this.map.isEmpty()) {

                                this.map = null;

                            }

                        }

                        break;

                    }

                }

            }

        }

    }

其它相关代码(相关接口和Bean[相关属性包含]):

public interface PropertyChangeListener extends java.util.EventListener {

    void propertyChange(PropertyChangeEvent evt);

}

public interface EventListener {

}

public class PropertyChangeEvent extends java.util.EventObject;

public class EventObject implements java.io.Serializable

如上所示,只要实现propertyChange方法即可实现属性改变时触发对应的动作。

firePropertyChange的源码分析:

    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {

        if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {

            firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));

        }

    }

private Object source;

    public void firePropertyChange(PropertyChangeEvent event) {

        Object oldValue = event.getOldValue();

        Object newValue = event.getNewValue();

        if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {

            String name = event.getPropertyName();

            PropertyChangeListener[] common = this.map.get(null);

            PropertyChangeListener[] named = (name != null)? this.map.get(name): null;

            fire(common, event);

            fire(named, event);

        }

    }

    // 此处如果有多个Listener就执行多次

    private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {

        if (listeners != null) {

            for (PropertyChangeListener listener : listeners) {

                listener.propertyChange(event);

            }

        }

    }

总结:对当前bean的属性添加Listener,当属性值改变时触发对应的Listener的执行。通过以上分析可以得知PropertyChangeSupport它内部维护了一个私有的map对象,而且在添加或者移除Listener时也是同步的,因此它是线程安全的类。