解决方案 »

  1.   

    嗯,说的没错。
    但是目前的问题是:在观察者那端(也就是我这里的B项目),怎么讲自己添加到主题端的观察者列表中呢,目前这块比较难懂
    管理观察者的类应该提供注册成观察者的方法的
    无非就是
    List<IObserver > lstObserver = new ArrayList<IObserver >();
    public void register(IObserver ob){
            lstObserver .add(ob);
    }
    保证这个方法B项目能调用到就行了
      

  2.   

    我现在参照上面的想法整理了一下伪代码:---------------A 项目------
    @Service
    public class ConfigServiceImpl extends ServiceImplBase {
              // 该方法会通过一定时器定时查询并返回当前服务状态,即ServiceStatusBean
              public ServiceStatusBean registerService(ServiceConfigBean config) throws TException {   
                //注册服务配置
               ServiceStatusBean serviceStatusBean = serviceConfigHander.registerConfig(config);
               System.out.println("观察者共有: " + this.getWatcherList().size());   // 这里始终都是 0,也就是说B观察者没有注册进来
               return serviceStatusBean;
        }
    }---------------B项目---------------
    @Service
    public class TimeStampServiceImpl extends ServiceImplBase implements IObserver {
            public TimeStampServiceImpl (){
              this.regist(this); 
           }
    }然后,我在这俩项目公有继承的类ServiceImplBase 中,加入了主题的代码:
    ----------------ServiceImplBase.java----------------
    public  class VRVServiceImplBase implements Subject{
       private List<IObserver> watcherList = new ArrayList<IObserver>();
       @Override
    public void AddWatcher(IObserver   o) {
    watcherList.add(o);
    }
    @Override
    public void DelWatcher(IObserver  o) {
    watcherList.remove(o);
    }
    @Override
    public void NotifyObserver() {
    for(IObserver    o: watcherList){
    watcher.Update();
    }
    } public List<IObserver> getWatcherList() {
    return watcherList;
    }
    }
    这样在A里边始终取到的观察者列表数据都是 0,不知道为毛线,求指教
      

  3.   

    B要向A注册?这还不简单,B把自己写进一个共享文件里给A读,写进公共数据库里给A读,写进公共缓存服务器里给A读,写进公共的配置服务器里给A读。挑一个吧
      

  4.   

    更正一下上面B项目中的伪代码:---------------B项目---------------
    @Service
    public class TimeStampServiceImpl extends ServiceImplBase implements IObserver {
            public TimeStampServiceImpl (){
              this.AddWatcher(this); 
           }
    }
      

  5.   


    你不在同一个项目里,是不能那样注册的。
    两个项目要共享数据,按照我上面的描述去考虑
    不需要这么麻烦,其实Java的观察者模式完全可以做到,你可以去了解一下GOF - 观察者模式
      

  6.   

    两个项目,一般会部署在不同的服务器上。(即使在相同的服务器上也可能运行在不同JVM进程中,即使同一个JVM中,也可能是不同的ClassLoader对象进行的类加载。)
    所以,楼主,这里缺少一个通信机制。将消息传递给相关联的项目。如果是同一个项目中的两个不同的功能模块,那么,谈起模式来,这个模型最起码是简单的,考虑得东西也相对少些。
      

  7.   

    嗯,没错,其实就是同一个项目中的两个不同模块,只是这两个模块各自是一个project(通过Maven管理)便于维护嘛。
    能否给段伪代码
      

  8.   

    嗯,没错,其实就是同一个项目中的两个不同模块,只是这两个模块各自是一个project(通过Maven管理)便于维护嘛。
    能否给段伪代码已经告诉你了两个项目的共享数据没那么简单B把自己写进一个共享文件里给A读
    或者写进公共数据库里给A读
    或者写进公共缓存服务器里给A读
    或者写进公共的配置服务器里给A读。
      

  9.   

    没有帮忙啊我再重新描述一下问题吧:
    项目A中定时每秒更改bean(即 ServiceStatusBean)的值,项目B需要实时取该bean的值,该咋如何解决???ps:目前在项目B中也定时器了一下,貌似这样有很大的风险,很容易有时间差,不太科学
      

  10.   

    大致代码如下,实际应用请自己修改。public interface MyChangeListener extends java.beans.PropertyChangeListener{
    }@Service
    public class ConfigServiceImpl extends ServiceImplBase {
              // 该方法会通过一定时器定时查询并返回当前服务状态,即ServiceStatusBean
         public ServiceStatusBean registerService(ServiceConfigBean config) throws TException {   
                //注册服务配置
               ServiceStatusBean serviceStatusBean = serviceConfigHander.registerConfig(config);
             
               return serviceStatusBean;
        }    public void doSomeService(){
            //Do something
            //Trigger Event
            support.firePropertyChange("", 1, 2);
        }  private java.beans.PropertyChangeSupport support;   @PostContruct
       public void init(ApplicationContext context){
          support = new java.beans.PropertyChangeSupport();
          Map<String, MyChangeListener> beans = context.getBeansOfType(MyChangeListener.class);
          for(Map.Entry<String, MyChangeListener> entry : beans.entrySet()){
                support.addPropertyChangeListener(entry.getValue());
          }
       }
    }
    @Service
    public class TimeStampServiceImpl extends ServiceImplBase implements MyChangeListener{
             public void propertyChange(PropertyChangeEvent evt){
                      Object newVal = evt.getNewValue(), oldValue = evt.getOldValue();
                      String propertyName = evt.getPropertyName();
                      //TODO something for this event.
             }
    }
      

  11.   

    刚看到你是2个工程的项目要相互通信。
    比较优雅的方案有2个。
    第一种:B项目对外暴露一个webservice,A项目属性变动时访问此WebService即可通知。
    第二种:增加一个JMS服务容器,A项目建立一个订阅者的消息队列。B项目去监听A项目的消息队列。A有情况时发送消息到队列B即可收到,并做相应处理。注:此方法可以多个工程同时监听A的消息队列,也就是说谁关心A的变动谁就去监听A的消息队列。
    个人比较倾向于第二种方法。
      

  12.   

    嗯,首先非常感谢。
    仔细看了下你的第二种方案,貌似可以满足一定的需求,不过JMS没怎么用过。
    能否贴一段伪代码,加强理解一下第二种方案的思路,然后好有个研究的方向。
      

  13.   

    A项目 添加针对状态改变的监听器对象
    B项目 实现监听器的操作
    示例代码: /**
     * 状态变化监听器,当状态变化时出发监听器的方法
     */
    public interface StatusChangeListener{
    /**
     * 当前后两种状态发生变化时,触发该方法的调用
     * @param lastStatus 上一次的状态
     * @param currentStatus  当前状态
     */
    void onStatusChanged(ServiceStatusBean lastStatus, ServiceStatusBean currentStatus);
    }

    @Service
    public class ConfigServiceImpl extends ServiceImplBase {
    private ServiceStatusBean lastStatus;
    private List<StatusChangeListener> listeners = new ArrayList<StatusChangeListener>();
    // 该方法会通过一定时器定时查询并返回当前服务状态,即ServiceStatusBean
    public ServiceStatusBean registerService(ServiceConfigBean config) throws TException {
    // 注册服务配置
    ServiceStatusBean serviceStatusBean = serviceConfigHander.registerConfig(config);
    if(isChanged(lastStatus,serviceStatusBean)){
    fireStatusChanged(lastStatus,serviceStatusBean);
    }
    lastStatus = serviceStatusBean;
    return serviceStatusBean;
    }
    /** 
     * 比较两次状态,判断状态是否改变了
     * @param lastStatus 上一次的状态值
     * @param currentStatus 当前状态值
     * @return 状态是否发生变化
     */
    private boolean isChanged(ServiceStatusBean lastStatus, ServiceStatusBean currentStatus) {
    // TODO 实现状态是否发生变化的判断
    return false;
    }
    /**
     * 当前后两种状态发生变化时,触发该方法的调用
     * @param lastStatus 上一次的状态
     * @param currentStatus  当前状态
     */
    private void fireStatusChanged(ServiceStatusBean lastStatus, ServiceStatusBean currentStatus) {
    for(StatusChangeListener listener : listeners){
    listener.onStatusChanged(lastStatus, currentStatus);
    }
    }
    /**
     * 添加(注册)监听器对象,可以注册多个对象。
     */
    public void addStatusChangeListener(StatusChangeListener listener){
    listeners.add(listener);
    }
    } @Service
    public class TimeStampServiceImpl extends ServiceImplBase implements StatusChangeListener{
    // 此处待实现
    public void onStatusChanged(ServiceStatusBean lastStatus, ServiceStatusBean currentStatus) {
    // TODO 此处实现,当ServiceStatusBean状态发生变化时,对应的操作内容。
    }

    }程序初始化的时候,想办法调用 ConfigServiceImpl 的 addStatusChangeListener 方法 (TimeStampServiceImpl 对象作为参数),就可以完成楼主提出的功能了。
      

  14.   

    嗯,一直想把这种方案利用起来,貌似难点都在你那个没说明白的上面,怎么讲B工程中的TimeStampServiceImpl 添加到A工程的ConfigServiceImpl 中addStatusChangeListener 来是个关键
      

  15.   

    楼主的代码,实现类中都没有对应的接口类,所以,我这里也只能顺着用了。
    @Service
    public class TimeStampServiceImpl extends ServiceImplBase implements StatusChangeListener{

    @Resource
    private ConfigServiceImpl configServiceImpl;
    @PostConstruct
    public void init(){
    configServiceImpl.addStatusChangeListener(this);
    }

    // 此处待实现
    public void onStatusChanged(ServiceStatusBean lastStatus, ServiceStatusBean currentStatus) {
    // TODO 此处实现,当ServiceStatusBean状态发生变化时,对应的操作内容。
    }

    }
      

  16.   

    每个系统的都会有一个初始化的过程,一般都会专门写一些代码来完成初始化的过程。
    我写的这个代码,虽然能够完成楼主的要求,但是,不太符合项目的整体规划。
    具体怎么实现,选用哪种方案实现,要问项目经理或者技术经理的。
    如果这个项目是你用来练手或者熟悉Spring、熟悉观察者模式的,那么,随便怎么折腾都好。
      

  17.   


    我是不是没表达清楚,这里的ConfigServiceImpl 和 TimeStampServiceImpl 这俩类是分属于不同的java project里边的,而且都不是web工程,属于是java project,最终是通过jvm加载main运行的,所以你这里在TimeStampServiceImpl类里边引用ConfigServiceImpl是引用不到的,就算引用到了,也不再同一个进程里边吧(个人想法有不对的地方请指正)