Spring中存在大量的工具类,如:RMI相关的。Spring所提供的 RMI的支持大大简化了RMI的开发难度,不过通常我们都是采用配置的方式,通过标准的spring bean来使用它们,这样虽然简化了开发,但是也限制了一些灵活性。因为bean的属性都是在配置时设定的(如RMI客户端中的服务的URL),而有时我 们需要在运行时生成这些属性,这时其实只要我们直接使用这些工具类就可以了。
要在程序中直接使用RmiProxyFactoryBean,我们就必须了解spring是如何使用这个类为我们生成客户端代理的,然后在程序中使用与spring相同的调用方式。
RmiProxyFactoryBean是一个工厂类,平时我们通过spring获得的并不是这个工厂类的实例,而是用这个工厂类创建的proxy的实例,这个类实现了spring中标准的FactoryBean接口。FactoryBean接口中定义了三个方法:
| getObject() Return an instance (possibly shared or independent) of the object managed by this factory. |
| getObjectType() Return the type of object that this FactoryBean creates, or null if not known in advance. |
boolean | isSingleton() Is the bean managed by this factory a singleton or a prototype? |
我们通过getBean获取这类工厂Bean(实现了FactoryBean接口的Bean)时,spring并不会返回工厂类的实例,而是调用工厂类的getObject方法并把方法的返回值返回给我们。
这样你就明白了原来我们获得的RMI的Proxy是通过RmiProxyFactoryBean的getObject方法生成的。
这时你一定认为下面的程序就可以搞定了:
…
RmiProxyFactoryBean proxy=new RmiProxyFactoryBean();
proxy.setServiceInterface(Calculator.class);
proxy.setServiceUrl(url);
Calculator client=(Calculator)proxy.getObject();
System.out.println(client.add(1,1));
…
运行程序你会发现上面这段程序并不成功,程序会抛出java.lang.NullPointerException异常。
问题在哪里呢?研究一下你会发现RmiProxyFactoryBean还实现了spring的
InitializingBean接口,接口中包含一个方法
afterPropertiesSet
()
,在所有属性注入完成后spring会调用这个方法,因此上面的程序并没有完全正确的模拟spring的调用过程。
修改代码:
…
RmiProxyFactoryBean proxy=new RmiProxyFactoryBean();
proxy.setServiceInterface(Calculator.class);
proxy.setServiceUrl(url);
proxy.afterPropertiesSet();
Calculator client=(Calculator)proxy.getObject();
System.out.println(client.add(1,1));
…
这次终于成功了!
最后,此例告诉大家有时我们可以直接调用spring中的工具类,来完成我们的特殊需求,此时要注意的是正确模拟spring的对bean创建和调用过程。