how to inject Environment on application context - java

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!

Related

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.

Restrict spring resources based on active profiles

I have restricted creation of beans, based on the spring active profiles. So that, these cannot be accessible in Production environment.
<beans profile="test">
<bean id="testSwaggerConfig" class="com.example.rest.config.SwaggerConfig" />
</beans>
Similarly, how can I restrict resources based on the spring active profiles. So that, while accessing to the html pages I should get 404.
<mvc:resources mapping="/rest/*.html" location="/rest-doc/" />
I am passing the active profile from environment variable -Dspring.profiles.active (May be this info useful for someone)
You can define parameter bean for each profile like this
<bean name="profileParam" class="java.lang.String">
<constructor-arg value="/rest/*.html" />
</bean>
And place desired mapping in the param
Then use the param from profile like this
<mvc:resources mapping="#{profileParam}" location="/rest-doc/" />
Thus for differen profiles you have different mapping accessible

Can I have multiple bean interconnection versions with Spring?

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

Use of Ajax with SimpleFormCotroller in Spring MVC

I'm developing an application in JSP using SimpleFormController with Spring MVC 3.0.2 using Hibernate. Everything is fine. I'm also using Validator to validate forms on the server side. It's also going on well.
Now, I need to use Ajax as an example, when a country is selected from a drop down (<form:select><form:option></form:option></form:select>), the states corresponding to that country should be populated from the database in the state drop down.
I have done such things using Ajax in places but yet not with Spring MVC. I have gone through many tutorials/articles about SimpleFormController on Google but none of them were using Ajax. I couldn't find a single idea about how to use Ajax with SimpleFormController.
With annotated controllers (#Controller), the thing can be made easy because methods can be mapped using the #RequestMapping annotation (nevertheless I haven't yet used it but I think I can).
But with SimpleFormController, I don't have any precise idea about how to handle Ajax requests in the Spring controller (which methods to be mapped and how). With SimpleFormController, I'm usually associated with the onSubmit(), showForm() and referenceData() methods.
Could you please expose some thoughts on how can an Ajax request be made on SimpleFormController, which methods can be mapped and how? (I don't want the full code anymore. A very simple example (if and only if it's possible) or furthermore specific links where the use of Ajax with the SimpleFormController is explained would be quite enough for me to study).
You could always just have a separate #Controller to handle the ajax requests. If you can have custom jsp on the view, there is nothing stopping you from handling an ajax request on the page. Just bind the onchange event of the select box to an ajax call pointing to the other Controller you made.
In terms of keeping it bound to just that SimpleFormController, I don't think this is possible, but if you create a new RESTful controller that the form would use, other parts of the website will be able to use this new controller as well.
In complement to dardo's answer, using both spring MVC 2 and MVC 3 controllers is possible, but a bit tricky to set up.
In order to use both SimpleFormController and #Controller controllers in the same Spring context, I used to following definition :
<!-- ======== MVC Spring 3.x ======== -->
<!-- Scans within the base package of the application for #Components to configure as beans #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="com.your.package" />
<!-- Enables the Spring MVC #Controller programming model -->
<!-- It's a shortcut equivalent to the (more complete) bean definition below (see bean AnnotationMethodHandlerAdapter).-->
<!--<mvc:annotation-driven />-->
<!-- This HandlerAdapter will register spring 3.x controllers (#Controller) into the DispatcherServlet -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</array>
</property>
</bean>
<!-- This HandlerMapping allows to map urls defined in #RequestMapping annotations to the corresponding controllers -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>
<!-- ======== MVC Spring 2.x ======== -->
<!-- This HandlerAdapter will register spring 2.x controllers (#Controller) into the DispatcherServlet -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<!-- Url mapper -->
<bean id="urlMapper" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/foo.do" value-ref="fooController" />
<entry key="/bar.do" value-ref="barController" />
...
</map>
</property>
</bean>

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")

Categories