【问题标题】:Use spring beans from Serializable objects使用来自 Serializable 对象的 spring bean
【发布时间】:2014-06-27 11:57:00
【问题描述】:

我需要在远程机器上执行任务。
此任务是虚拟的 Runnable 或 Callable 和 Serializable 以传输到远程主机,反序列化并在那里执行。
我需要使用该任务中的 spring bean 在远程机器上执行它。

当任务在客户端机器上序列化并在远程机器上反序列化时“反序列化”真实 bean 时,“序列化”bean 名称的优雅方法是什么?
还有其他解决方案吗?

【问题讨论】:

  • 两台机器共享数据库?
  • 是的,你有什么建议?
  • 只需将实体的 id 发送到远程机器并加载到远程机器中,就像来自客户端-服务器 Web 应用程序的请求/响应一样

标签: java spring serialization


【解决方案1】:
    private static class MyCommand implements Callable<String>, Serializable {
        private static final long serialVersionUID = 8980820796677215627L;
        private transient SpringBean springBean;
        private String bar;

        public InitDoneRemoteCommand(SpringBean springBean, String bar) {
            this.springBean = springBean;
            this.bar = bar;
        }

        @Override
        public String call() {
            return springBean.foo(bar);
        }

        private void writeObject(java.io.ObjectOutputStream out) throws IOException {
            out.defaultWriteObject();
            out.writeObject(getBeanName(springBean));
        }

        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            springBean = getBean((String) in.readObject());
        }
    }

SpringContext.java

    @Resource
    public class SpringContext implements ApplicationContextAware, BeanPostProcessor, BundleContextAware, ServiceListener {
        private static ApplicationContext applicationContext;
        private static BundleContext bundleContext;
        private static Map<Object, String> springBeanToName = synchronizedMap(new WeakHashMap<Object, String>());
        private static Map<String, ServiceReference> osgiNameToServiceReference = synchronizedMap(new WeakHashMap<String, ServiceReference>());

        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }

        public static BundleContext getBundleContext() {
            return bundleContext;
        }

        @SuppressWarnings("unchecked")
        public static <T> T getBean(String name) {
            ServiceReference ref = osgiNameToServiceReference.get(name);
            if (ref != null)
                return (T) bundleContext.getService(ref);
            return (T) applicationContext.getBean(name);
        }

        public static String getBeanName(Object bean) {
            if (isOsgiBean(bean))
                return getOsgiBeanName(bean);
            return springBeanToName.get(bean);
        }

        public static boolean isOsgiBean(Object bean) {
            return bean instanceof ImportedOsgiServiceProxy || bean instanceof ServiceReferenceProxy || bean instanceof ServiceReference;
        }

        public static String getOsgiBeanName(Object proxy) {
            if (proxy == null)
                return null;
            ServiceReference serviceReference = null;
            if (proxy instanceof ImportedOsgiServiceProxy)
                serviceReference = ((ImportedOsgiServiceProxy) proxy).getServiceReference().getTargetServiceReference();
            else if (proxy instanceof ServiceReferenceProxy)
                serviceReference = ((ServiceReferenceProxy) proxy).getTargetServiceReference();
            else if (proxy instanceof ServiceReference)
                serviceReference = ((ServiceReference) proxy);
            if (serviceReference != null)
                return (String) serviceReference.getProperty(OSGI_BEAN_NAME_PROPERTY);
            throw new IllegalArgumentException(proxy.toString());
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            springBeanToName.put(bean, beanName);
            return bean;
        }

        @Override
        public void serviceChanged(ServiceEvent event) {
            ServiceReference ref = event.getServiceReference();
            String name = getOsgiBeanName(ref);
            if (event.getType() == ServiceEvent.REGISTERED)
                osgiNameToServiceReference.put(name, ref);
            else if (event.getType() == ServiceEvent.UNREGISTERING)
                osgiNameToServiceReference.remove(name);
        }

        @Override
        public void setApplicationContext(ApplicationContext context) throws BeansException {
            SpringContext.applicationContext = context;
        }

        @Override
        public void setBundleContext(BundleContext bundleContext) {
            SpringContext.bundleContext = bundleContext;
            bundleContext.addServiceListener(this);
        }
    }

【讨论】:

    【解决方案2】:

    如果您有权访问 ApplicationContext,您可以要求它为您创建实例,例如启用自动装配:

    appContext.getAutowireCapableBeanFactory().createBean(
        beanClass, 
        AbstractBeanDefinition.AUTOWIRE_BY_TYPE, 
        true)
    

    更优雅的方法是使用@Configurable 注释类,描述为here

    【讨论】:

      猜你喜欢
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 1970-01-01
      • 2016-12-24
      • 2014-11-23
      • 1970-01-01
      • 2011-08-28
      相关资源
      最近更新 更多