Restrict spring resources based on active profiles - java

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

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.

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!

Cloud properties not read by Spring application in Cloudfoundry

I am deploying a Spring application in Cloudfoundry which needs to access mysql database. Now as per the tutorial , if the spring version is higher than 3.1, i can use profiles for the cloud and the cloud properties will be available for the application. The mysql service is registered as p-mysql in my case so my spring config looks like this
<beans profile="cloud">
<context:property-placeholder location="classpath:/app.conf" />
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
p:location="file:#{systemProperties['app.conf']}" />
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!-- DB connection properties -->
<property name="driverClass" value="${db_driver:oracle.jdbc.OracleDriver}" />
<property name="jdbcUrl" value="${cloud.services.p-mysql.connection.jdbcUrl}" />
<property name="user" value="${cloud.services.p-mysql.connection.username}" />
<property name="password" value="${cloud.services.p-mysql.connection.password}" />
</bean>
</beans>
I need the app.conf for other keys not related to db services. When i deploy this i get the error
OUT org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'datasource' defined in URL [jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/test-server-1.3.0.BUILD-SNAPSHOT.jar!/spring-bootstrap.xml]: Could not resolve placeholder 'cloud.services.p-mysql.connection.jdbcUrl'
Is there something i missed , when i look for the env for app, i do see the properties are available for the app (cf env app_name)
What i could have missed? do i have to include
cloudfoundry-runtime in the pom which i dont have now?
or include the cloud namespace in the spring app
Any documentation that mentions cloudfoundry-runtime is obsolete. The current documentation recommends the use of Spring Cloud Connectors for Spring applications on Cloud Foundry.
You should include Spring Cloud Connectors in your project, then you could do something as simple as this:
<cloud:data-source id="datasource" service-name="mysql-service"/>
You could also create the datasource bean yourself using property placeholders if you really need more control. Additional documentation on configuring Spring Cloud Connectors via XML is here: https://github.com/spring-cloud/spring-cloud-connectors/tree/master/spring-cloud-spring-service-connector#the-cloud-namespace

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

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