質問
Spring を使用してリモートサーバーへの RMI 呼び出しを処理しています。アプリケーション コンテキストを構築し、クライアント内からリモート呼び出し用の Bean を取得するのは簡単です。
ApplicationContext context = new ApplicationContext("classpath:context.xml");
MyService myService = (MyService ) context.getBean( "myService " );
ただし、プロパティを構成に渡す簡単な方法がわかりません。たとえば、クライアント内で実行時にリモート サーバーのホスト名を決定したい場合です。
Spring コンテキストに次のようなエントリがあれば理想的です。
<bean id="myService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://${webServer.host}:80/MyService"/>
<property name="serviceInterface" value="com.foo.MyService"/>
</bean>
そしてプロパティをクライアントからパラメータとしてコンテキストに渡します。
コンテキスト内で PropertyPlaceholderConfigurer を使用してこれらのプロパティを置き換えることができますが、私の知る限り、これはファイルから読み取られたプロパティに対してのみ機能します。
これに対処する実装があります(回答として追加)が、独自の実装を避けるために標準のSpring実装を探しています。構成の初期化に役立つ別の Spring コンフィギュラー (またはその他) はありますか、それともこれを実現するには Java 構成を調べたほうがよいでしょうか?
解決
アップデート:
質問の更新に基づいて、私の提案は次のとおりです。
- を作成します
ServiceResolver
クライアント入力に基づいて処理する必要があるものはすべて処理する Bean。 - この Bean を関連サービスへの依存関係として宣言します。
- 実行時に、必要に応じてこの Bean を更新または使用できます。
の ServiceResolver
その後、次のいずれかの方法で行うことができます init-method
または、呼び出しごとに、たとえば、次の値に基づいて、クライアントに返す値を決定します。JNDI ルックアップまたは環境変数。
しかし、その前に、次のことを確認してください。 構成オプション 利用可能。次のいずれかを行うことができます。
- コンパイル時に存在する必要のないプロパティ ファイルを追加します。
- JNDI から値を検索します。
- System.properties から値を取得します。
カスタムの場所からプロパティを検索する必要がある場合は、以下を参照してください。 org.springframework.beans.factory.config.BeanFactoryPostProcessor
そしてどのようにして org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
が実装されています。
基本的な考え方は、「生」のプロパティを持つ Bean を取得することです。 ${jdbcDriverClassName}
その後、それらを解決して、目的の値に置き換えます。
他のヒント
http://forum.springsource.org/showthread.php?t=を参照してください。 71815 の
TestClass.java
package com.spring.ioc; public class TestClass { private String first; private String second; public String getFirst() { return first; } public void setFirst(String first) { this.first = first; } public String getSecond() { return second; } public void setSecond(String second) { this.second = second; } }
SpringStart.java
package com.spring; import java.util.Properties; import com.spring.ioc.TestClass; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; public class SpringStart { public static void main(String[] args) throws Exception { PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer(); Properties properties = new Properties(); properties.setProperty("first.prop", "first value"); properties.setProperty("second.prop", "second value"); configurer.setProperties(properties); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); context.addBeanFactoryPostProcessor(configurer); context.setConfigLocation("spring-config.xml"); context.refresh(); TestClass testClass = (TestClass)context.getBean("testBean"); System.out.println(testClass.getFirst()); System.out.println(testClass.getSecond()); } }
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="testBean" class="com.spring.ioc.TestClass"> <property name="first" value="${first.prop}"/> <property name="second" value="${second.prop}"/> </bean> </beans>
出力:
first value second value
私の既存のソリューションは、追加のコンストラクタの引数として地図を取る新しいMapAwareApplicationContextの定義が含まれます。
public MapAwareApplicationContext(final URL[] configURLs,
final String[] newConfigLocations,
final Map<String, String> additionalProperties) {
super(null);
//standard constructor content here
this.map = new HashMap<String, String>(additionalProperties);
refresh();
}
これはMapAwareProcessorに追加するpostProcessBeanFactoryを()より優先されます:
protected void postProcessBeanFactory(
final ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new MapAwareProcessor(this.map));
beanFactory.ignoreDependencyInterface(MapAware.class);
}
MapAwareProcessorはMapAwareインタフェースを実装する任意の型にマップを注入する)(postProcessBeforeInitializationを実装します
public Object postProcessBeforeInitialization(final Object bean,
final String beanName) {
if (this.map != null && bean instanceof MapAware) {
((MapAware) bean).setMap(this.map);
}
return bean;
}
私はその後MapAwarePropertyPlaceholderConfigurerを宣言するために私の設定に新しいBeanを追加します:
<bean id="propertyConfigurer"
class="com.hsbc.r2ds.spring.MapAwarePropertyPlaceholderConfigurer"/>
構成器はMapAwareを実装するので、上記のように地図を注入します。これは、親コンフィギュラにマップ、または代理人からプロパティを解決するためにresolvePlaceholder()を実装しています:
protected String resolvePlaceholder(final String placeholder,
final Properties props, final int systemPropertiesMode) {
String propVal = null;
if (this.map != null) {
propVal = this.map.get(placeholder);
}
if (propVal == null) {
propVal = super.resolvePlaceholder(placeholder, props);
}
return propVal;
}
PropertyPlaceholderConfigurerはそれが本当、ファイルからプロパティを取得することができますが、それはそれらを見つけることができない場合、それはシステムプロパティを使用するようにフォールバックします。これは、クライアントアプリケーションのための実行可能な選択肢のように聞こえる、ちょうどあなたがクライアントを起動するときに-Dを使用して、システムのプロパティを渡します。
<のhref = "http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html" のrel = "nofollowをnoreferrer" から> javadocのの
コンフィギュラもに対してチェックされます システムプロパティ(例えば「はuser.dir」)もし それが持つプレースホルダを解決することはできません 指定されたプロパティのいずれか。この 経由してカスタマイズすることができます "systemPropertiesMode" ます。
RmiProxyFactoryBean
インスタンスを作成し、コード内で直接serviceUrl
プロパティを設定します:
String serverHost = "www.example.com";
RmiProxyFactoryBean factory = new RmiProxyFactoryBean();
factory.setServiceUrl("rmi://" + serverHost + ":80/MyService");
factory.setServiceInterface(MyService.class);
try {
factory.afterPropertiesSet();
} catch (Exception e) {
throw new RuntimeException(
"Problem initializing myService factory", e);
}
MyService myService = (MyService) factory.getObject();