My question is about which configuration strategy I should use for my Java Spring application which runs multiple threads in a clustered environment.
The hierarchy of the application is like this:
Main application files & config
|
|__Parent module files & config
|
|__Child module files & config
I have a DataProvider which is #Transactional:
#Transactional
public class DataProvider {
protected Configuration configuration;
public DataProvider(Configuration configuration, DummyArg1 arg1, DummyArg2 arg2) {
this.configuration = configuration;
createResult();
addMoreStuffFromModules();
}
private void createResult() {
this.result.setSomeStuff = "someStuff";
}
private void addMoreStuffFromModules() {
this.result.setSomeMoreStuff = configuration.getModuleDataProvider.getData();
}
}
Main application configuration:
<bean id="dataProvider" abstract="true" class="com.main.DataProvider">
<constructor-arg ref="main-configuration"/>
<constructor-arg ref="main-dummyArg1"/>
<constructor-arg ref="main-dummyArg2"/>
</bean
<bean id="main-Configuration" class="com.main.Configuration" /> <!-- just an empty class in main application -->
Parent module configuration:
<bean id="dataProvider" abstract="true" class="com.main.DataProvider">
<constructor-arg ref="parent-configuration"/>
<constructor-arg ref="parent-dummyArg1"/>
<constructor-arg ref="main-dummyArg2"/>
</bean
<bean id="parent-Configuration" class="com.parent.Configuration" />
As you can see. Parent module needs to provide new bean for dataProvider and all constructor arguments to be able to inject its own configuration into the Data Provider class.
This is the same for the child module:
<bean id="dataProvider" abstract="true" class="com.main.DataProvider">
<constructor-arg ref="child-configuration"/>
<constructor-arg ref="parent-dummyArg1"/>
<constructor-arg ref="main-dummyArg2"/>
</bean
<bean id="child-Configuration" class="com.child.Configuration" />
Is this a good strategy? I think it's not. Because what happens if the parent configuration updates (for example sets configuration to reference another bean)? Then we would want the child configuration to automatically get that new reference in the constructor-arg.
I would prefer if its possible, to have the configuration for the modules only set the constructor args as they want to change (not the other args), for example like this:
<bean id="dataProvider" abstract="true" class="com.main.DataProvider">
<constructor-arg ref="child-configuration"/>
<!-- arg1 inherited from parent and/or main configuration -->
<!-- arg2 inherited from parent and/or main configuration-->
</bean
<bean id="child-Configuration" class="com.child.Configuration" />
Any ideas on how to achieve this?
If you make the Configuration a bean, you can just override that bean in the child modules and simply not override the DataProvider bean.
Update
Java based configuration example, as I don't use XML configs:
Suppose you have 3 beans that DataProvider needs:
#Component
public class Configuration {
// main config here
}
#Component
public class OtherData {
}
#Component
public class MoreData {
}
And a Data provider like this:
#Component
public class DataProvider {
#Inject private Configuration conf;
#Inject private OtherData otherData;
#Inject private MoreData moreData;
}
Then in your other module do:
#Component #Primary
public class ChildConfiguration extends Configuration {
// different config here
}
... and you will have overriden only the Configuration part without changing the other two parts.
Related
I have this class that creates an application context from XML:
public class SpringModel {
public SpringModel(Object dependency) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(...);
Foo foo = (Foo) applicationContext.getBean("foo");
}
}
The bean named "foo" has a constructor that looks like this:
public Foo(Object dependency) {
...
}
I want to inject the argument from SpringModel's constructor into the constructor for Foo. Is this possible?
If you're using an xml based application context you could define the dependencies like
<beans>
<bean id="dependencyObj" class="Object"/>
<bean id="springModelObj" class="SpringModel">
<constructor-arg ref="dependencyObj"/>
</bean>
<bean id="foo" class="Foo">
<constructor-arg ref="dependencyObj" />
</bean>
</beans>
It might also be easier to have your Foo object reference be a private variable in the SpringModel class with an appropriate setter method. Then you could link it to the SpringModel bean in the xml configuration with a property tag.
I have a problem with my code trying to generate #Autowired.
The Class:
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
#Autowired
ConsultasMDMWSPortype consultasMDMWSPortype;
public ConsultarClienteResponseMDM consultarClienteEnMdm(ConsultarClienteRequest clienteReq) {
ConsultarClienteResponseMDM response = new ConsultarClienteResponseMDM();
ConsultasMDMWSService consultasMDMWSService = new ConsultasMDMWSService();
ConsultarClienteResponse clienteResp = null;
clienteResp = consultasMDMWSPortype.consultarCliente(clienteReq);
ListaCursoresMDM listaCursores;
listaCursores = new ObjectMapper().readValue(clienteResp.getListaCursoresResponse(), ListaCursoresMDM.class);
response.getListaCursoresResponse().add(listaCursores);
return response;
}
}
My applicationContext.xml
<context:annotation-config/>
<context:component-scan base-package="pe.com.claro.eai.esb.ws.jira.mdm"/>
<import resource="wsclients-config.xml"/>
My wsclients-config.xml
<bean id="consultasMDMWSPortype" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="pe.com.claro.eai.consultasmdmws.ConsultasMDMWSPortype"/>
<property name="wsdlDocumentUrl" value="http://limdeseaiv28.tim.com.pe:8909/ConsultasMDMWS/ConsultasMDMPortSB11?wsdl"/>
<property name="namespaceUri" value="http://eai.claro.com.pe/ConsultasMDMWS"/>
<property name="serviceName" value="ConsultasMDMWSService"/>
<property name="portName" value="ConsultasMDMPortSB11"/>
<property name="lookupServiceOnStartup" value="false"/>
</bean>
<bean id="consultasMDMWSClient"
class="pe.com.claro.eai.esb.ws.jira.mdm.service.client.ConsultasMDMWSClientImpl">
<property name="consultasMDMWSPortype" ref="consultasMDMWSPortype"/>
</bean>
I don't know what I'm doing wrong, I've mapped everything like an example of my work
I'm new on Spring, my web method works without Spring.
The error just appear when I use #Autowired.
java.lang.NullPointerException
Thaks everyone.
As an alternative to solution proposed by #Christopher, if you want to keep the "old-style" XML configuration injection (setter injection) you need to remove #Autowired annotation and declare a setter to ConsultasMDMWSPortype, ie:
ConsultasMDMWSPortype consultasMDMWSPortype;
and
public ConsultasMDMWSPortype setConsultasMDMWSPortype(ConsultasMDMWSPortype consultasMDMWSPortype) {
this.consultasMDMWSPortype = consultasMDMWSPortype;
}
So spring will be able to wire the ref-bean configured in xml, through the setter method.
You can try to add #Component annotation on top of ConsultasMDMWSClientImpl class.
Like:
#Component
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
This is needed to indicate that this is a spring bean, so that the spring container scan it and initialize as a spring bean while starting the spring container.
I hope it helps.
As already pointed out, you're mixing XML wiring with annotation wiring. The simplest solution is to take away the #Autowired of the Portype and instead inject ConsultasMDMWSClient in other beans:
#Controller
public class MyController {
#Autowired
ConsultasMDMWSClient client;
}
Another solution would be remove the wiring in XML and just inject portype in your client:
#Component
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
#Resource
protected ConsultasMDMWSPortype consultasMDMWSPortype;
}
Once again, you inject the client in other beans.
In any case, you shouldn't be hardwiring the JAX-WS settings in literals, you should replace them with values in properties files and prepare different properties files for different environments. For example:
<bean id="consultasMDMWSPortype" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="${jaxws.serviceInterface}"/>
<property name="wsdlDocumentUrl" value="${jaxws.wsdlDocumentUrl"/>
</bean>
Just replaced #Autowired by #Qualifier.
Thanks for the help.
I have a follofing situation int "super-context.xml":
<bean id="conf" class="ee.Conf"/>
<bean id="service" class="ee.Serivce">
<property name="conf" ref="conf">
</bean>
Now I want to use this "super-context.xml" in various different projects. Say "sub-context.xml" has:
<import resource="super-context.xml"/>
<bean id="subConf1" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconf1.sss" />
</bean>
<bean id="subConf2" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconf2.sss" />
</bean>
...
<bean id="subConfn" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconfn.sss" />
</bean>
ee.Conf is something as follows:
public class Conf ... {
...
public void addSubConf(Resource res) {
//configuration resolving from res
}
...
}
ee.SubConf is something as follows:
public class SubConf ... {
...
#Autowired
ee.Conf superConf;
...
public void setConfloc(Resource res) {
superConf.addSubConf(res);
}
...
}
The problem aries on context load. Beans are initialized in following order (due to ordering in context file): conf, service, subConf1, subConf2, ... subConfn
But service bean actually depends on all the subConf beans (although this can't be deducted from the context definition itself). It loads OK when import in "sub-context.xml" is added after subConf bean definitions.
Reason behind this is implementing modularity. Is it possible to force a bean to load as late as possible ("service" bean in the example) or make beans of certain type load as soon as possible ("subConf" beans in the example), since fixed ordering of beans in "sub-context.xml" partly kills the wished modularity
Or is theree a more pure way to achieve this type of modularity?
I would say that you are approaching the problem in a wrong way. The SubConf shouldn't have a dependency on the Conf to start with. Simply inject the collection of SubConf objects in your Conf object.
public class Conf {
#Autowired
private List<SubConf> subconfs;
}
That way you eliminate the need for the SubConf to call the Conf class and this will remove your circular dependency.
See the Spring reference guide for more information on autowiring.
You can use depends-on
<bean id="beanOne" class="foo.Bar" depends-on="beanTwo" />
In my application I am using ContextLoaderListener to load context files from many jars using:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>
This means I can reference beans from other jars without doing import.
In the application there are multiple deployment options and in some deployments jars can be excluded. To support that I would like some bean references to be optional. For example:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1" ref="optionalBeanReference1"/>
<constructor-arg index="2" ref="optionalBeanReference2"/>
</bean>
In the example above I would like to have optionalBeanReference1 equal null if the reference was not found (mark it optional in some way)
Can this be done in Spring? or what method do you recommend for handling dynamic references?
My best guess is to use autowire-ing with required false. Don't know how you can express this in XML but using annotation configuration this would look like:
#Autowired(required=false)
With recent versions of Spring (tested with spring 4.1) and Java Configuration and Java 8, you can use Optional in parameters, and are only autowired if available.
#Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
// do something with the optional autowired
}
what method do you recommend for handling dynamic references?
I think #cristian's #Autowired answer is a good one. That will call the setter methods if the beans of that type are available. However, if you have multiple beans of the same type, I believe Spring throws an exception. If you cannot use #Autowired for this or some other reason, I see a couple of solutions:
You could make your class ApplicationContextAware and lookup the beans in the context yourself:
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.containsBean("optionalBeanReference1")) {
setOptionalBeanReference1(
(OptionalBeanReference1)applicationContext.bean(
"optionalBeanReference1");
}
...
}
You could invert the dependency. Each of the optional classes could set themselves on the mainAppBean. I use this in certain situations when a direct dependency would cause loops or other problems.
<bean id="optionalBeanReference1" class="com.someapp.SomeClass">
<constructor-arg index="0" ref="mainAppBean"/>
</bean>
Then in the SomeClass:
public SomeClass(com.someapp.MyApplication mainAppBean) {
mainAppBean.setOptionalBeanReference1(this);
}
You could stay with your direct dependency and then either import a file with the beans defined or import another file where you define the beans as having null values by using a factory bean. See this factory code.
Good luck.
There's no built-in mechanism for this. However, you could write a pretty trivial FactoryBean implementation to do this for you, something like this:
public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {
private String beanName;
#Override
public void setBeanName(String beanName) {
this.beanName = BeanFactoryUtils.originalBeanName(beanName);
}
#Override
protected Object createInstance() throws Exception {
if (getBeanFactory().containsBean(beanName)) {
return getBeanFactory().getBean(beanName);
} else {
return null;
}
}
#Override
public Class<?> getObjectType() {
return null;
}
}
You can then use it like this:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1">
<bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
<constructor-arg index="2">
<bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
</bean>
Given that the bean references in your XML config are defined via expression language (EL) you can do the following:
<property name="cache" value="#{getObject('optionalCache')}" />
which makes use of the BeanExpressionContext.getObject() method. See here for more details.
How can i inject a properties file containing a Map to be used as additional constructor arg using the field.
With a Map being loaded from a properties file
the bean is currently setup using:
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value= "data/neo4j-db"/>
<constructor-arg index="1" value=? />
</bean>
Java Equivalent:
Map<String,String> configuration = EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
Thanks
Something like this:
<bean id="configuration" class="org.neo4j.kernel.EmbeddedGraphDatabase"
factory-method="loadConfigurations">
<constructor-arg value="neo4j_config.props"/>
</bean>
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value="data/neo4j-db"/>
<constructor-arg index="1" ref="configuration" />
</bean>
This takes advantage of the ability to create beans using arbitrary static factory methods, in this case using loadConfigurations() as a factory method to create the configuration bean, which is then injected into the proper constructor of EmbeddedGraphDatabase.
Create a bean that loads the properties (and takes the file name as an argument) and inject that instead.
EDIT When using annotations, things like constructor injection become more simple:
#Bean
public Map<String,String> configuration() {
return EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
}
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration() );
}
Note that the second bean definition method "simply" calls the first. When this code is executed, Spring will do some magic so you can still override the bean elsewhere (i.e. beans still overwrite each other) and it will make sure that the method body will be executed only once (no matter how often and from where it was called).
If the config is in a different #Configuration class, then you can #Autowired it:
#Autowired
private Map<String,String> configuration;
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
}