Spring & MyBatis - how to get MyBatis databseId in a #Bean annotated function - spring

I am trying to create a Spring bean based on a MyBatis databaseId like so:
#Bean
fun getSomeBean(#Autowired databaseId: String): SomeBean {
if(databaseId.equals("mysql")){
return SomeMySqlBean()
} else {
return SomeNonMysqlBean()
}
}
How do I get the databaseId to be injected with MyBatis?

I had a look at some of the API documentation and came up with this - works nicely and now I can construct a couple of the vendor-specific objects I need:
#Bean
fun databaseId(sqlSessionFactory: SqlSessionFactory): String {
return sqlSessionFactory.configuration.databaseId
}

Related

Switch bean by changing properties in Spring boot

I have one interface MyInterface, and 2 implementation beans: FirstImpl & SeconImpl. I want to switch between using these 2 implementations while program is running without restarting it, by only changing a property in application.properties file, e.g: interface.bean.default=FirstImpl change to interface.bean.default=SecondImpl.
Anyone knows how to do that with Spring boot?
You could try to use #ConditionalOnProperty:
#Configuration
public class MyInterfaceConfiguration {
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="firstImpl")
public MyInterface firstImpl(){
return new FirstImpl();
}
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="secondImpl")
public MyInterface secondImpl(){
return new SecondImpl();
}
}
and when you update your property in application.properties with actuator/refresh to:
my.interfacte.impl=firstImpl
you will have your FirstImpl instance. When you have:
my.interfacte.impl=secondImpl
you will have your SecondImpl.
#Hasan, your update only works if I customize it a little bit as below:
#Configuration
#RefreshScope
public class MyInterfaceConfiguration {
#Value("${my.interfacte.impl}")
String impl;
#Bean
#RefreshScope
public MyInterface getBean(){
if ("firstImpl".equals(impl)) {
return new FirstImpl();
} else if ("secondImpl".equals(impl)) {
return new SecondImpl();
}
return null;
}
}
I have to use 2 #RefreshScope at class level and bean creation method level!

How to declare an optional #Bean in Spring?

I want to provide an optional #Bean in my #Configuration file like:
#Bean
public Type method(Type dependency) {
// TODO
}
when dependency can't be found, the method should not be called.
How to do that?
You need to use ConditionalOnClass If using SpringBoot and Conditional in Spring since 4.0 See If using Spring
Example of SpringBoot :-
#Bean
#ConditionalOnClass(value=com.mypack.Type.class)
public Type method() {
......
return ...
}
Now the method() will be called only when com.mypack.Type.class is in classpath.
In addition to the accepted answer, you have to check if the dependency is initialized before calling any method which requires that dependency.
#Autowired(required = false)
Type dependency;
public Type methodWhichRequiresTheBean() {
...
}
public Type someOtherMethod() {
if(dependency != null) { //Check if dependency initialized
methodWhichRequiresTheBean();
}
}

Spring batch with spring data

Is there a way to integrate spring batch with spring data? I see RepositoryItemReader and RepositoryItemWriter in spring documentation.
You are totally right. Spring batch can be easily be integrated with spring data. Here example of item reader:
#Bean(name = "lotteryInfoReader")
#StepScope
public RepositoryItemReader<LotteryInfo> reader() {
RepositoryItemReader<LotteryInfo> reader = new RepositoryItemReader<>();
reader.setRepository(lotteryInfoRepository);
reader.setMethodName("findAll");
reader.setSort(Collections.singletonMap("name", Sort.Direction.ASC));
return reader;
}
Here is another example with using hibernate without spring data :
#Bean(name = "drawsWriter")
#StepScope
public ItemWriter<? super List<Draw>> writer() {
return items -> items.stream()
.flatMap(Collection::stream)
.forEach(entityManager::merge);
}
well i'm doing that in a different way i'm injecting the service into the job configuration and invoke the method that's available on the JpaRepository, like this example
#Bean
#StepScope
public ItemWriter<Customer> customerItemWriter2() {
return items -> {
for (Customer item : items) {
customerService.save(item);
}
};
}

Working with #Qualifier in Kotlin functions

In Kotlin function parameters are always values which prevents #Qualifier() from being used at the parameter level.
If someone wanted to create multiple DataSources in a config class for different databases frequently accessed within the same application what is the recommended way to organize this?
Doing the following which seemed fairly common in Java isn't allowed in Kotlin.
#Configuration
class DatabaseAdminConfig {
#Bean
#ConfigurationProperties(prefix = "spring.ds_admin")
fun adminDataSource(): DataSource {
return DataSourceBuilder.create().build()
}
#Bean
fun adminJdbcTemplate(#Qualifier("adminDataSource") dsAdminDb: DataSource): JdbcTemplate {
return JdbcTemplate(dsAdminDb)
}
#ConfigurationProperties(prefix = "spring.ds_widget")
fun widgetDataSource(): DataSource {
return DataSourceBuilder.create().build()
}
#Bean
fun widgetJdbcTemplate(#Qualifier("widgetDataSource") widgetDataSource: DataSource): JdbcTemplate {
return JdbcTemplate(widgetDataSource)
}
}
There is no need to inject the dependency from the same class into the method that requires that dependency in Spring. You can just call the method directly.
#Configuration
class DatabaseAdminConfig {
#Bean
#ConfigurationProperties(prefix = "spring.ds_admin")
fun adminDataSource() = DataSourceBuilder.create().build()
#Bean
fun adminJdbcTemplate() = JdbcTemplate(adminDataSource())
#Bean
#ConfigurationProperties(prefix = "spring.ds_widget")
fun widgetDataSource() = DataSourceBuilder.create().build()
#Bean
fun widgetJdbcTemplate() = JdbcTemplate(widgetDataSource())
}
PS: function expression bodies (as above) make Spring Configuration classes look even more concise.
PPS: #Qualifier works totally fine for me. I just tested it.
PPPS: And for completeness to address the specific problem, as I commented: You must have accidentally imported the javax.inject.Qualifier annotation, which will not work. You need to import the org.springframework.beans.factory.annotation.Qualifier which works

Togglz with Spring #Configuration bean

I'm trying to implement Togglz & Spring using #Configuration beans rather than XML. I'm not sure how to configure the return type of the Configuration bean. For example:
#Configuration
public class SystemClockConfig {
#Bean
public SystemClock plainSystemClock() {
return new PlainSystemClock();
}
#Bean
public SystemClock awesomeSystemClock() {
return new AwesomeSystemClock();
}
#Bean
public FeatureProxyFactoryBean systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return proxyFactoryBean;
}
}
The systemClock method returns a FeatureProxyFactoryBean but the clients of this bean require a SystemClock. Of course, the compiler freaks over this.
I imagine it just works when XML config is used. How should I approach it when using a configuration bean?
I'm not an expert for the Java Config configuration style of Spring, but I guess your systemClock() method should return a proxy created with the FeatureProxyFactoryBean. Something like this:
#Bean
public SystemClock systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return (SystemClock) proxyFactoryBean.getObject();
}
But I'm not sure if this is the common way to use FactoryBeans with Spring Java Config.

Resources