I have the following Spring bean for a remote web service defined in xml:
<bean id="authWSTemplate" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean" abstract="true">
<property name="serviceInterface" value="com.example.webservices.Authentication" />
<property name="wsdlDocumentUrl" value="${ws.root}/authentication?wsdl" />
<property name="namespaceUri" value="http://security.webservices.example.com/" />
<property name="serviceName" value="AuthenticationWebService" />
<property name="portName" value="AuthenticationPort" />
<property name="maintainSession" value="true" />
</bean>
How do I obtain this bean template and create a concrete bean (i.e. supply the root property)? Can I then put the concrete bean into the Spring container?
I need numerous concrete beans pointing to different systems, so I have different root values. For this example, say there are 2 systems with roots: http://domain1.com:8001/ws and http://domain2.com:8002/ws.
Therefore I'd want 2 beans called "authWSdom1" and "authWSdom2".
I'm expecting to do this programmatically in an application initialisation block, where I'd retrieve a list of all known system implementations (this info is only known at runtime), and create a bean for each impl, cache the bean name, then my application will retrieve the appropriate bean from the Spring container when required.
Or, is there a better pattern for this? Perhaps by providing the root value in a constructor for the bean?
I'm thinking I cannot have a single bean in Spring as I need to support concurrent access across multiple end points (i.e. multiple users hitting domain1 and domain2 at the same time).
Create custom bean that implements BeanFactoryPostProcessor and InitializingBean.
Use postProcessBeanFactory method to create bean:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
String wsdlDocumentUrl = ....;
// .......
registry.registerBeanDefinition(YOUR_BEAN_NAME, BeanDefinitionBuilder.childBeanDefinition(
getParentNoDomainServicBeanName(authWSTemplate)).addPropertyReference(
"wsdlDocumentUrl", wsdlDocumentUrl).getBeanDefinition());
}
While I believe that Ragnor's answer is suitable if you want to dynamically create the bean in the spring container, I decided to use spring to define my own WSTemplate DTO then use a factory class to use this DTO and programmatically build (root url provided at runtime and DTO suffix value added to it) and cache the resulting JaxWS ProxyBean:
<bean id="authWSTemplate" class="com.example.WSProxyTemplate">
<property name="serviceInterface" value="com.example.webservices.Authentication" />
<property name="wsdlDocumentUrlSuffix" value="/authentication?wsdl" />
<property name="namespaceUri" value="http://security.webservices.example.com/" />
<property name="serviceName" value="AuthenticationWebService" />
<property name="portName" value="AuthenticationPort" />
<property name="maintainSession" value="true" />
</bean>
I like this approach as my spring config is abstracted away from the actual WS bean used. I.e. if I wanted to use something other that JaxWS, then I'd simply write a different factory which used the same DTO beans. Again, this would help if I have to choose the WS implementation at runtime depending upon some system/env criteria.
Related
Can Spring bean be a reference to another bean? It doesn't seem to work:
<bean id="player1" class="some.package.Player" />
<bean id="player2" ref="player1" />
If this is possible, is it useful? So far, I was thinking that every bean must represent a unique object, but some idea came to my head: what if I had a Singleton class called e.g. Sun with a "public static Sun getInstance()" method and I would make two beans being the same object?
<bean id="sun1" class="some.package.Sun" factory-method="getInstance" />
<bean id="sun2" class="some.package.Sun" factory-method="getInstance" />
Looking at the below
<bean id="player1" class="some.package.Player" />
<bean id="player2" ref="player1" />
I think you want to refer same bean with two or more names. If so, you can have comma separated list or ids as (alias concept)
<bean id="player1, player2" class="some.package.Player" />
Now you can refer the bean with either player1 or player2.
Similarly,
<bean id="sun1" class="some.package.Sun" factory-method="getInstance" />
<bean id="sun2" class="some.package.Sun" factory-method="getInstance" />
can be replaced with
<bean id="sun1, sun2" class="some.package.Sun" factory-method="getInstance" />
and this allows you to refer the same bean with two different ids.
And to understand when aliasing is useful, quoting from https://vladmihalcea.com/why-i-like-spring-bean-aliasing/,
Bean aliasing allows us to override already configured beans and to
substitute them with a different object definition. This is most
useful when the bean definitions are inherited from an external
resource, which is out of our control.
Beans are generally singletonic, so they represent one object per context. Standard singleton design pattern in java creates one object per class loader. I think in your case you will re-create one object twice, once with Spring beans, and once with own class loader executed implementation. So both suns will be the same when you compare their hash codes via .getInstance().hashCode().
Would it be possible to convert this config to a single #Configuration class? I need to pick the values for Car from property files
<bean name="VW" class="com.app.car">
<property name="cost" value="${vw.cost}"/>
<property name="power" value="${vw.power}"/>
</bean>
<bean name="Merc" class="com.app.car">
<property name="cost" value="${merc.cost}"/>
<property name="power" value="${merc.power}"/>
</bean>
<bean name="FirstCar" class="com.app.cart">
<property name="car" ref="VW"/>
</bean>
<bean name="SecondCar" class="com.app.cart">
<property name="car" ref="Merc"/>
</bean>
I know we can define different classes fro VW and Marc and then refer #Autowire them to a parent #Configuration class. Wondering if there is a solution involving defining all these beans in a single class. I tried using #Value for parameters for devAppConfig as below
vw(#Value("vw.cost") String cost, #Value("vw.power") String power)
merc(#Value("merc.cost") String merc, #Value("merc.power") String power)
But these methods have input parameters. Having 2 different objects of the same type that need to be instantiated with different property values and injected as dependencies is the goal
You can use Spring Profiles, so you can have a property file o bean for each enviroment.
Spring Profiles provide a way to segregate parts of your application
configuration and make it only available in certain environments. Any
#Component or #Configuration can be marked with #Profile to limit when
it is loaded You can see more here
http://www.baeldung.com/spring-profiles
http://www.mkyong.com/spring/spring-profiles-example/
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
I am trying to write a ValidatorFactory which will give me a validator based on its type
public Validator getNewValidator(ValidatorType type){
switch:
case a : new Validator1();
break;
case b : new Validator2();
break;
}
I want to write using spring xml beans definition
I can use method injection but it will let me create only one object and the method does
not take any arguments.
I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml
bean definition.
you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.
<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>
<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />
And the content of the property file would be:
validatorType=validatorTypeOne
To use the property file in your xml just add this context to the top of your spring config
<context:property-placeholder location="classpath:app.properties" />
For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.
If you are using annotation (#Autowired, #Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to #Qualifier does not support expression
#Qualifier(value="${validatorType}")
More information is at https://stackoverflow.com/a/7813228/418439
I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:
<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg type="int" value="256"/>
</bean>
<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="${password.encoding}Password"/>
</bean>
</property>
</bean>
Of course, I defined password.encoding in a property file with possible values as sha or plainText.
You should be able to do this:
<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
<constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>
<bean id="validatorType" ... />
Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.
I want to inject currentUser instance in HomeController class. so for every request, HomeController will have currentUser object.
My configuration:
<bean id="homeController" class="com.xxxxx.actions.HomeController">
<property name="serviceExecutor" ref="serviceExecutorApi"/>
<property name="currentUser" ref="currentUser"/>
</bean>
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
But I am getting following error.
Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.currentUser': Target type could not be determined at the time of proxy creation.
at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:94)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
What is the problem? and Is there any better/simple alternative?
Cheers.
With scoped-proxies, Spring still needs to know the type of the bean when the context is initialized, and in this case it's failing to do so. You need to try and give it more information.
I notice that you're only specifying factory-bean in your definition of currentUser, with no factory-method specified. I'm actually rather surprised that that's a valid definition, since the two are normally used together. So try adding the factory-method attribute to currentUser, which specifies the method on userProviderFactoryBean which creates the user bean. That method needs to have a return type of your User class, which Spring will use to infer the type of currentUser.
Edit: OK, after your comment below, it seems you've misunderstood how to use factory beans in Spring. When you have a bean of type FactoryBean, you don't need to use the factory-bean attribute as well. So instead of this:
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
You just need this:
<bean id="currentUser" class="com.xxxxx.UserProvider" scope="session">
<aop:scoped-proxy/>
<property name="userDao" ref="userDao"/>
</bean>
Here, UserProvider is a FactoryBean, and Spring knows how to handle that. The end result will be that the currentUser bean will be whatever UserProvider generates, rather than an instance of UserProvider itself.
The factory-bean attribute is used when the factory is not a FactoryBean implementation, but just a POJO, and it allows you to tell Spring explicitly how to use the factory. But because you're using FactoryBean, there's no need for this attribute.
I have two xml files defining beans for the springframework (version 2.5.x):
containerBase.xml:
<beans>
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
</list>
</property>
</bean>
</beans>
... and
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
</beans>
Now I want to adjust the property sourceCodeLocations of bean codebase within containerSpecial.xml. I need to add a second value src/generated/productive.
A simple approach is to override the definition of codebase in containerSpecial.xml and add both values, the one from containerBase.xml and the new one:
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
Is there a way to extend the list without redefining the bean?
EDIT 2009-10-06:
The purpose of this is to have a shared standard container containerBase that is used by a lot of different projects. Each project can override/extend some properties that are special for that project in its own containerSpecial. If the project doesn't override, it's using the defaults defined in containerBase.
You could use a BeanFactoryPostProcessor to change the bean's metadata before the Spring container instantiates the CodeBase bean. For example:
public class CodebaseOverrider implements BeanFactoryPostProcessor {
private List<String> sourceCodeLocations;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
CodeBase codebase = (CodeBase)beanFactory.getBean("codebase");
if (sourceCodeLocations != null)
{
codebase.setSourceCodeLocations(sourceCodeLocations);
}
}
public void setSourceCodeLocations(List<String> sourceCodeLocations) {
this.sourceCodeLocations = sourceCodeLocations;
}
}
Then in contextSpecial.xml:
<beans>
<import resource="context1.xml" />
<bean class="com.example.CodebaseOverrider">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
Yes. A bean definition can have a "parent" attribute that references a parent bean definition. The new "child" definition inherits most of the properties of the parent and any of those properties can be overridden.
See Bean Definition Inheritance
Also you can use Collection Merging to merge the list property definition from the parent and child bean definitions. This way you can specify some list items in the parent bean definition and add more items to it in the child bean definition.
Is there a way to define the list in a properties or other configuration before hand?
It seems like the app configuration and wiring are tightly coupled. From my experience, if it is hard to do something in Spring, likely there is a different easier way to do it.
3 approaches:
Simple: have two lists defaultSourceCodeLocations and additionalSourceCodeLocations and have your accessor methods check both of these (or combine them). I've seen this done in some frameworks - a default list of handlers is populated then additional user created ones are added...
More complicated but keeps the original class clean: You could then create a CodeBaseModifier class. This would have a init-method to alter an injected instance of the bean.
<bean id="codebaseModifier" class="com.example.CodeBase" init-method="populateCodeBase">
<property name="sourceCodeLocations" ref="codebase"/>
<property name="additionalSourceCodeLocations">
<list>
<value>src/handmade/productive</value>
</list>
</property>
</bean>
If you wanted to make this really generic you could make a bean modifier that would do this by reflection. Be careful of the ordering if use this approach. Dependent beans of CodeBase would have to make sure this class was instantiated first (with depends on)
3 A variation on 2... Instead of directly creating a CodeBase class instead create a factory that returns a populated bean. This factory could then be configured with Spring in a similar fashion to 2. Have a defaultSourceCodeLocations and additionalSourceCodeLocations
Unless you need a lot of extensible properties I would go with option 1.
In Spring 3.0, you can specify merge="true" on the 'list' tag. See http://forum.springsource.org/archive/index.php/t-97501.html for details.