Declare beans for all profiles except one, using Spring profiles (XML) - java

I'd like to know, using Spring XML profiles, if it is possible to declare Spring beans for all profiles, except the dev profile.
My usecase is that I would like to declare my JDBC datasource as being JNDI provided for profile "dev", while it is created for other profiles.
I'd like to have something like:
<beans profile="dev" >
... DataSource JNDI ...
</beans>
<beans profile="!dev" >
... DataSource creation ...
</beans>
Is there a solution? Or the only way is to do:
<beans profile="dev" >
... DataSource JNDI ...
</beans>
<beans profile="integration,valid,preprod,prod" >
... DataSource creation ...
</beans>
Thanks

You can use !, for spring version higher than Spring 3.2 M1.
So this way is ok:
<beans profile="!dev" >
... DataSource creation ...
</beans>

A simpler way would be like this:
General datasource creation for any profile:
<bean name="datasource" ...>
then specific for dev:
<beans profile="dev" >
<bean name="datasource" ...>
</beans>

Related

BeanFactoryLocator alternative in Spring 5

We were using 4.2.x version of spring and we are using BeanFactoryLocator to create a factory from xml file.
method to return Beanfactory:
private BeanFactory createServicesContainer() {
BeanFactoryLocator bfLocator = SingletonBeanFactoryLocator.getInstance("Connector.xml");
BeanFactoryReference bfReference = bfLocator.useBeanFactory("bigBean");
return bfReference.getFactory();
}
my Connector.xml file contains:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="false">
<!--
The Big Bean for accessing all the repository services. This factory bean serves as
and umbrella bean for all the underlying repository services.
-->
<bean id="bigBean" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>sample1-connector.xml</value>
<value>sample2-connector.xml</value>
<value>sample3-connector.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
Now how can make changes it to work in Spring 5.x

Conditionally load a bean in spring boot using xml configuration?

I am using Spring Boot 2.1.
I have some mixed configuration in my project : XML files and java classes with annotations.
We have this current configuration which works :
application.properties :
spring.profiles.active=dev, component1, component2
applicationContext-file.xml :
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="component1">
<beans>
<bean id="myserviceimpl"
class="org.blabla.MyServiceImpl">
<property name="mydao">
<ref bean="mydao"></ref>
</property>
</bean>
</beans>
</beans>
We want to extract the component values from the spring.profiles.active property since they have nothing to do with the environment :
application.properties :
spring.profiles.active=dev
component1=true
component2=true
How can i condition the instantiation of the myserviceimpl bean inside the applicationContext-file.xml ?
I can no longer rely on the profile attribute since the spring.profiles.active property no longer includes
the values of the components.
Thanks for helping.
I haven't tried it by myself but I suggest to check the following:
Step 1
Create one XML file per profile (say, dev and prod for the sake of example):
app-config-dev.xml:
------------------
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="dev">
<beans>
<!-- here define only beans that you want to load in __dev__ environment -->
<bean id="myserviceimpl"
class="org.blabla.MyServiceImpl">
<property name="mydao">
<ref bean="mydao"></ref>
</property>
</bean>
</beans>
</beans>
app-config-prod.xml:
------------------
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="prod">
<beans>
<!-- here define only beans that you want to load in __production__ environment -->
<bean id="myserviceimpl"
class="org.blabla.MyServiceProdImpl">
<property name="mydao">
<ref bean="mydao"></ref>
</property>
</bean>
</beans>
</beans>
Step 2
Now in your "primary" applicationContext-file.xml instead of defining beans directly, include all the xml files that you've created during the step 1:
<import resource="classpath:app-config-dev.xml" />
<import resource="classpath:app-config-prod.xml" />
Read this thread for more details on this step if needed
Step 3
Remove the component1=true and component2=true from aplication properties, you don't need it anymore, the profile itself defines which beans should be loaded.
Update 1
Based OP's first comment:
You probably can try another option but I consider it a "low-level" solution and it requires deep understanding of how does spring loading process work under the hood.
So when spring starts it finds the definitions of beans (in xml, java config, annotations like #Component and so forth) and creates out of all this information a BeanDefinition - a metadata object that aggregates all the information about the bean (for example whether its singleton or prototype). At this point no beans are not created yet. Lets call this point in time a "Bean Definitions Done" point" (for the sake of explanations, its my term out of my head...
Then spring starts to build a graph of dependencies and starts creating beans, initializing them (Autowiring, post-construct methods, and so on) and placing them onto application context (if they're singletons).
Now, in spring there is an option to provide a hook called BeanFactoryPostProcessor that is invoked exactly at the "Bean Definitions Done" point. This is basically a java code that implements some interface and by itself is a spring bean that spring treats in a special way.
So you can implement this interface and manipulate the results of Bean factory.
Namely you can access every bean definition that spring has opened and if you think that the bean of this definition should not be created (here comes your custom logic that would check properties, whatever) - remove the bean definition from the registry:
For technical method of removing bean definitions see this thread
Here is an example of Bean Factory Post processor that actually adds a new bean although it wasn't registered

Autowired spring bean null for cacheManager using ehcache spring annotations

I'm still new to spring and I'm trying to get ehcache spring annotations setup correctly. I'm using Spring 3.2.3 ehCache 2.4 and ehcache-spring-annotations-1.2.
When I try to access the reference to the cacheManager, it is always null. All the jars are on the build path, ehcache.xml is in the classpath and there are no xml errors. I've tried also including the classes in the component scan and using #Resource instead of Autowired. I'm stuck!
Application context:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
ehcache-spring-1.1.xsd">
<context:component-scan base-package="org.springframework.cache.ehcache.EhCacheManagerFactoryBean,com .defaultPackage,net.sf.ehcache.CacheManager" />
<!-- ehCache Annotation settings -->
<ehcache:annotation-driven cache-manager="ehCacheManager" />
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
<property name="shared" value="true"/>
</bean>
Wrapper
#Component
public final class MyCache implements Serializable {
#Autowired
private CacheManager ehCacheManager;
private getCacheManager() {
return ehCacheManger; // this is always null
}...}
It seems you are trying to use the EhCacheManagerFactoryBean as your cache manager.
Looking at Spring caching documentation, you need to declare another bean to be your CacheManager created from the factory.

How to create beans by condition in xml?

I'm creating the following bean using xml config:
<int-ip:tcp-outbound-gateway id="gate"
request-channel="input"
reply-channel="clientBytes2StringChannel"
connection-factory="factory"/>
How can I configure this based on a condition, eg a value included in application.properties?
I spring 4 I could use #ConditionalOnExpression("SpEL"), but how could I achieve the same in xml?
You can use Spring Profiles to conditionally create beans. For e.g.
<beans profile="dev">
<bean id="devDatasourceConfig" class="" />
</beans>
<beans profile="production">
<bean id="productionDatasourceConfig" class=" " />
</beans>
You can activate profiles as follows:
JVM system parameter:
-Dspring.profiles.active=dev
or
Environment variable:
export spring_profiles_active=dev

#Transactional annotation doesn't work

ok, enough. I couldn't make this work. I am a newbie to Spring transactions and using the #Transactional annotation in my service to manage transactions. Below is my spring bean configuration file.
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myapp"/>
<!-- other <bean/> definitions here -->
</beans>
and I annotate my service:
#Transactional
public class MyServiceImpl implements MyService {
...
}
I notice two things
The connection that I get in my DAO [using DataSourceUtils.getConnection(dsName)] has the autocommit enabled [true].
As far as I debugged there doesn't look to be any transaction that has begun during my service method invocation.
Anyone had this problem?
I use Hibernate with the HibernateTransactionManager myself, so I'm not too familiar with how the JDBC transaction manager works. Have you inspected the callstack to see whether or not TransactionInterceptor is in there ? If it is, then the transactional annotation is working, and you may just be missing something else. If you haven't looked for it, what makes you think that it's not working ? To eliminate the obvious, have you explicitly set a setting in your JDBC configuration to disable autocommit ?

Categories

Resources