Can I have multiple bean interconnection versions with Spring? - java

Spring configuration file creates beans and interconnects them. Is this correct? I have a chain of beans in my application but want to test it with smaller chains. Can I have multiple chains defined with Spring? Or only one bean structure is allowed?
EXAMPLE
Suppose this is production config:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="processor1" class="tests.Processor1">
<property name="input" ref="provider"/>
</bean>
<bean id="processor2" class="tests.Processor2">
<property name="input" ref="processor1"/>
</bean>
<bean id="consumer" class="tests.Consumer">
<property name="input" ref="processor2"/>
</bean>
And I want to test in the following configs:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="analyzer" class="tests.Analyzer">
<property name="input" ref="provider"/>
</bean>
And:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="processor1" class="tests.Processor1">
<property name="input" ref="provider"/>
</bean>
<bean id="analyzer" class="tests.Analyzer">
<property name="input" ref="processor1"/>
</bean>
And so on, attaching beans one by one.

Yes, you can.
You can break overall configuration of Spring application context for your application into parts (XML files if you use XML configuration, packages with #Components if you use classpath scanning, #Configurations if you use Java-based configuration) and construct an application context using a subset of these parts.
So, if your application has two features foo and bar, you can declare beans used by these features in foo.xml and bar.xml respectively (if you use XML configuration), and import them from the main configuration of your application (such as applicationContext.xml).
Now, if you want to write integration test for bar you can create application context from bar.xml only (#ContextConfiguration("bar.xml")). Obviously, you should take care of interdependencies between different parts of your configuration. For example, if both foo.xml and bar.xml depend on beans declared in db.xml, you may want to create something like test-db.xml and configure your integration test for bar as #ContextConfiguration({"bar.xml", "test-db.xml"}).
Note that this approach requres some discipline, especially if you use classpath scanning - in this case parts of your configuration are defined by packages, therefore you need to follow "package by feature, not by layer" rule.
See also:
9.3 Integration testing

I believe you want to test for integration, what I usually do is to separate my bean configuration files in tiers and then import them as needed for testing. Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:property-placeholder
location="classpath:mx/gob/jgtjo/apps/schedule/web/schedule-web.properties"
file-encoding="UTF-8" system-properties-mode="NEVER" />
<!-- Context files -->
<import resource="spring/dataContext.xml" />
<import resource="spring/serviceContext.xml" />
<import resource="spring/securityContext.xml" />
<import resource="spring/components.xml" />
</beans>
And then, if I need to test for Daos, I only import the dataContext.xml inside a testContextDao.

In simple terms spring framework takes care of Object Creation. These objects you want Spring to manage you define them as beans. So when spring creates a bean1 if that bean1 has reference to bean2, the bean2 is instantiated and injected to bean1 and finally bean1 is created. Thinking of it as chain will be over complicating.
Section 3.2 of spring docs

Related

Spring : Initialization of properties before any bean creation

I have the project structure as following -
Facade -> Service-> DAO
In the DAO layer, when the beans are initialized then many dependencies are injected from a property file. Therefore, the properties file must be read first and then the remaining dao beans must be created. When the application is started then it gives an error that Spring cannot resolve a placeholder.
The DAO-application-context.xml is like-
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
<import resource = "a-dao.xml" />
<import resource = "b-dao.xml" />
<import resource = "c-dao.xml" />
Now in all the child application contexts i.e. a-dao, etc, we have-
<bean ....>
<property name = "xyz">
<value>${appValue}<value/>
</property>
<bean>
The error received is that appValue cannot be resolved. I think that it may be due to incorrect sequence of bean creation. However, the same config is working in another larger project.
I have checked Order of Spring Bean Initialization but implementing that solution would not be feasible. Is there any other way ?
Reg this Block of Configuration, property prop seems to be wrong
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
According to the Spring documentation
You could use the property location or locations to set the one or multiple values of the properties file.
So the code should be refactored to
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>app.properties</value>
</property>
</bean>

How to register Spring Cloud config server before any XML bean is declared?

I am trying to migrate a spring app who uses PropertyPlaceholderConfigurer to resolve all the XML placeholders in it's bean declarations to a spring cloud usage, I can check that the config server is contacted and responds with the respective data generated from a git repository, however, at server startup during the BeanFactoryPostProcessor registration the XML context fails to resolve the placeholders.
I assumed that by removing the bean definition:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="properties">
<bean class="org.apache.commons.configuration.ConfigurationConverter"
factory-method="getProperties">
<constructor-arg>
<ref bean="domainConfiguration" />
</constructor-arg>
</bean>
</property>
</bean>
And adding the POM dependency for config client and respective enviroment variables the placeholders should work but they dont.
Can I manually set the config server in a higher priority?
Or as an alternative, teach PropertyPlaceholderConfigurer to consume a config server?
If you are using spring-cloud-config, this should work out of the box. When spring will build/start the ApplicationContext, first it will create a bootstrap (parent) context which will happen before creating the main context. Getting the properties of the config server should happen in the bootstrap phase so that your beans which are created in the normal context should be able to get those properties.
Check out the Client Side Usage part of the documentation for an example and check out the usage of the bootstrap.properties file.
If you don't have spring-boot (it should work w/o it as well but the docs are spring-boot centric), check out this repo or this GitHub issue, you will need a ConfigServicePropertySourceLocator.

how to inject Environment on application context

I'm currently working with legacy code and I wanna read some properties from the Environment. I know this would be easily done using spring boot with:
#Autowired
Environment environment;
But, since I'm wiring all the components using an application-context.xml file, I don't know how to wire the Environment there,
<bean name="myBean" class="com.acme.MyClass">
???
</bean>
Thanks for your help #volveira89 #rmlan
Using the xml file, this is working:
<bean name="myBean" class="com.acme.MyClass">
<constructor-arg ref="environment"/>
</bean>
It seems that you have no experience in Spring XML config. You should look at this example by Spring team: https://spring.io/blog/2011/01/04/green-beans-getting-started-with-spring-mvc/
You need something like this in your application-context.xml:
<!-- Scans within the base package of the application for #Components
to configure as beans -->
<!-- #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="xyz.sample.baremvc" />
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
Now your,
#Autowired
Environment environment
should work!

Spring TransactionInterceptor with multiple TransactionManager

In a webapplication I am using different components which are all using Spring 3.0.x having their own DataSource and TransactionManager (all with different names). They are all included in the context via the "main" webapp via including their spring config.
<import resource="classpath:spring-config-componentName.xml" />
In each of the Spring configs of the components I am using declarative transaction management, enabled via
<tx:annotation-driven transaction-manager="transactionManager_componentName" />
And for each method that should be transactional I add a annotation that looks like this:
#Transactional(propagation=Propagation.REQUIRES_NEW, value="transactionManager_componentName")
The problem I have is that I found out that only one TransactionInterceptor is created which has a reference to one of the transactionManagers but not of the one of the component itself. Is there a way to handle this? Like to specify a TransactionInterceptor as a bean and then reference it in the #Transactional annotation?
I think there is a possibility by specifying a TransactionProxyFactoryBean in each component and doing the declarative transaciton management via the xml config. But this is something I would like to avoid.
The proposed way as described in the Spring docs (10.5.6.2 Multiple Transaction Managers with #Transactional) does not work.
Finally I found out what the problem was and I have to say that it works as it is described in the spring docs.
If you are using more than one TransactionManagerin your Spring Container and you are using #Transactionit does not work if you are specifiying the TransactionManager like this:
<tx:annotation-driven transaction-manager="transactionManager_componentName" />
All you have to do ist to remove the specification of the TransactionManager and use a configuration like this:
<!-- ========== ENABLE ANNOTATIONS ========== -->
<tx:annotation-driven/>
<!-- ========== TRANSACTION MANAGER ========== -->
<bean id="transactionManager_component1"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource_component1" />
<property name="nestedTransactionAllowed" value="true" />
<qualifier value="component1"/>
</bean>
And for you methods you want to run in a transaction then just specify it like this:
#Transactional(value="component1")

Declaring an explict object dependency in Spring

The basic problem I have here is that I have one xml file that is being used as a utility file and imported into other xml files. It defines a series of objects for connecting to a platform and providing an interface to it. The beans in this file are defined to be lazy-initialised so that if you do not want to connect to the platform you will not but if you start referencing the appropriate bean then everything should get up and running.
The basic problem I have is that one of the beans in this set is not explicity referenced by any of the others but it is required to be constructed as it will call a method on one of the other beans in order to "activate" it. (It is acting as a gate keeper by switching on/off the connectivity based on what it detects as the state of the platform).
Here's a dummy of the sort of XML setup I have:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"
default-lazy-init="true">
<!-- Provides the connection to the platform -->
<bean id="PlatformConnection">
<constructor-arg ref="PlatformConnectionProperties" />
</bean>
<!-- This bean would be overriden in file importing this XML -->
<bean id="PlatformConnectionProperties"/>
<!-- Controls the databus to be on/off by listening to status on the Platform
(disconnections/reconnections etc...) -->
<bean lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<!-- A non platform specific databus for client code to drop objects into -
this is the thing that client XML would reference in order to send objects out -->
<bean id="PlatformConnectionDataBus" class="DataBus"/>
<!-- Connects the DataBus to the Platform using the specific adaptor to manage the java object conversion -->
<bean lazy-init="false" class="DataBusConnector">
<constructor-arg>
<bean class="PlatformSpecificDataBusObjectSender">
<constructor-arg ref="PlatformConnection" />
</bean>
</constructor-arg>
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
</beans>
Now basically I want to remove the lazy-inits here that are required to get this thing to work properly. The objects referenced by the client XML are the PlatformConnection and the PlatformConnectionDataBus. How can I explicity declare that I want those other beans constructed if they are referenced?
You can add an explicit dependency from one bean to another by using the depends-on attribute:
<bean id="a" class="A"/>
<bean id="b" class="B" depends-on="a"/>
If I'm understanding your questin correctly, then I suggest you make all of your bean definitions lazy-init="true", and use depends-on to tie them together, for example:
<bean id="PlatformStatusNotifier" lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<bean id="PlatformConnectionDataBus" lazy-init="false" class="DataBus" depends-on="PlatformStatusNotifier"/>
So if your client config were to express a dependency on PlatformConnectionDataBus, then that would trigger the initialisation of PlatformConnectionDataBus, which in turn would trigger the initialisation of PlatformStatusNotifier.

Categories