Spring boot: add an external configuration file - java

I am trying to build a new annotation based spring boot application.
On the DAO-level I have a configuration class with Dao beans:
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public DataSource dataSource(){
...
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(){
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource());
return template;
}
#Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
....
}
#Bean
public PersonDao personDao(){
return new PersonDao();
}
}
On the server level a controller and a Mein class.
#SpringBootApplication (exclude = SecurityAutoConfiguration.class)
#ComponentScan("my.package")
#Import(DataBaseConfig.class)
public class Main {
private static Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
The problem is that the main class does not see the beans got from the DatabaseConfig and that's why cannot start the application (because they are user in the controller). How can I correctly import them?

Related

how to load #Configuration classes in an order in spring boot

i would like to load #Configuration classes in an order. i have two configuration classes. i am having a requirement of loading my SampleProperties class before sampleconfiguration class.
I have tried the following annotations but it is not working as expected.
#AutoConfigureAfter(SampleProperties.class )
#AutoConfigureBefore(SampleConfiguration.class)
I have put my congiurations class in diff package in order to read configurations classes in an order.using #Import function, i am including my configuration classes into my application
My Main Class:
#Import({SampleProperties.class,SampleConfiguration.class,})
public class SampleApplication{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
My SampleProperties Class
#Configuration
#AutoConfigureBefore(SampleConfiguration.class)
#ConfigurationProperties("demo")
#Data
public class SampleProperties {
private String team;
private int teamSize;
private String teamLeader;
}
My sampleconfiguration Class:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef="sampleEntityManager",
transactionManagerRef="sampleTransactionManager",
basePackages= {"com.example.demo.repo"})
#AutoConfigureAfter(SampleProperties.class)
public class SampleConfiguration {
#Autowired
Environment env;
#Bean(name="sampleDataSource")
#Primary
public DataSource dmsDataSource() {
// functions
return null;
}
#Primary
#Bean(name = "sampleEntityManager")
public LocalContainerEntityManagerFactoryBean dmsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
// functions
return null;
}
#Primary
#Bean(name = "sampleTransactionManager")
public PlatformTransactionManager dmsTransactionManager(#Qualifier("sampleEntityManager") EntityManagerFactory entityManagerFactory) {
// functions
return null;
}
}
can anyone tell me what missing and where am making mistakes?
I think you have to use #Order annotation.
#Component
#Order(1)
public class SampleProperties {
// code
}
#Component
#Order(2)
public class SampleConfiguration {
// code
}

#autowired annotation for service class is not working in #configure class spring boot

when i am using #autowire to inject my dependencies in Configuration
class its giving me as null please refer the code below .
#Configuration
public class DataSourceConfig {
#Autowired
AppService appService;
#Bean
public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
createBeans(beanRegistry);
}
};
}
private void createBeans(BeanDefinitionRegistry beanRegistry,DataSourceConfigService ds) {
appService.getDbDetails();
appService is null here if i will call it using this way
BeanDefinitionRegistryPostProcessor beanPostProcessor(AppService
appService) then in AppServiceImpl class AppDao dependency will be null
}
}
//// Service
#Service
public class AppServiceImpl implements AppService{
#Autowired
AppDao ds;
#Override
public List<A> getDatabaseConfiguration() {
return ds.getDbDetails(); // here ds is null
}
}
//dao
#Repository
public class AppDaoImpl implements AppDao {
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
#Override
public List<A> getDbDetails() {
return nameParamJdbcTemplate.query(SELECT_QUERY, new DataSourceMapper()); // nameParamJdbcTemplate is null
}
// datasource config
#Configuration
public class DataSourceBuilderConfig {
#Bean(name = "dbSource")
#ConfigurationProperties(prefix = "datasource")
#Primary
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "nameParamJdbcTemplate")
#DependsOn("dbSource")
#Autowired
public NamedParameterJdbcTemplate jdbcTemplate1(#Qualifier("dbSource") DataSource dbSource) {
return new NamedParameterJdbcTemplate(dbSource);
}
}
What i want is when ever my beanPostProcessor()
is executed i want all my dependent beans should be instantiated ie
#Autowired
AppService appService;
#Autowired
AppDao ds;
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
I am new to spring so any help or working examples would be great. Thanks
It is null because this #Configuration class also defines a BeanDefinitionRegistryPostProcessor that forces the context to create that bean very early on.
Because you are using field injection, the context has to resolve AppService bean but it can't yet because the post-processor have to be applied first.
Your configuration looks very complex so you may want to simplify it a bit:
Separate low-level infrastructure configuration from main configuration
Always define such post processor as public static method so that the context can invoke the #Bean method without having to construct the class first.

SpringBoot beanFactory.getBean(PlatformTransactionManager.class) is very slow

springboot auto config TransactionManager and SqlFactory, it works well ,but when i use #Transactional the program wait in a daze, i flow the code and find
beanFactory.getBean(PlatformTransactionManager.class) is very slow.
but when i add this:
#Autowired
private PlatformTransactionManager platformTransactionManager;
it works. so what's the problem. i have no idea, and i'm using grpc with springboot now, please help thx;
#Configuration
#SpringBootApplication
#ComponentScan(value = "cn.com.autohome.autopay.wallet")
#EnableTransactionManagement
#EnableAutoConfiguration
#EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AppMain extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(AppMain.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(AppMain.class);
}
}
#Configuration
#MapperScan(basePackages = "cn.com.autohome.autopay.wallet.core.dal.mapper")
#ImportResource(locations = {"classpath:wallet-dal-bean.xml"})
public class WalletMyBatisConfig {
#Autowired
private DataBaseProperties dataBaseProperties;
#Primary
#Bean(name = "walletDataSource")
#ConfigurationProperties("spring.datasource.druid")
public DataSource masterDataSource() throws SQLException {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
dataSource.setDriverClassName(dataBaseProperties.getWallet_data_source_driver_class());
dataSource.setUrl(dataBaseProperties.getWallet_data_source_url());
dataSource.setUsername(dataBaseProperties.getWallet_data_source_username());
dataSource.setPassword(dataBaseProperties.getWallet_data_source_password());
return dataSource;
}
}

Checking Redis #Configuration in SpringBoot

Is there a way to check if #Configuration components are being loaded when run a spring boot app ?
I have some 'null pointer' problems when i use this app:
Main class
#ComponentScan(basePackages = "com.pack")
#EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Configuration class
package com.pack.config;
#Configuration
public class DataBaseConfig {
#Bean
JedisConnectionFactory jedisConnFactory() {
return new JedisConnectionFactory();
}
#Bean
public StringRedisSerializer stringRedisSerializer() {
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
return stringRedisSerializer;
}
#Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(jedisConnFactory());
redisTemplate.setKeySerializer(stringRedisSerializer());
return redisTemplate;
}
}
And when i try to use RedisTemplate:
public class ServiceDummy {
#Autowired
RedisTemplate<String, Object> redisTemplate;
public void save(String data){
redisTemplate.opsForValue().set("1234", data);
}
}
im getting a nullPointer.
As #Todd correctly pointed out, you can't expect Spring to manage beans that are not registered to Spring context.
So you need to:
Mark that bean as Spring bean with #Component annotation, or in this case #Service annotation would be better.
Make sure that ServiceDummy is under com.pack package, so that Spring can scan that component.

Spring Boot ConflictingBeanDefinitionException: Annotation-specified bean name for #Controller class

I keep getting the ConflictingBeanDefinitionException error in my Spring boot application. I am not entirely sure as to how to address it, I have several #Configuration annotated classes helping to set up Thymeleaf, Spring Security and Web. Why is the application trying to setup the homeController twice? (and where is it trying to do this?)
The error is:
org.springframework.beans.factory.BeanDefinitionStoreException:
Failed to parse configuration class [org.kemri.wellcome.hie.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'homeController' for bean class [org.kemri.wellcome.hie.HomeController] conflicts with existing, non-compatible bean definition of same name and class [org.kemri.wellcome.hie.controller.HomeController]
My spring boot main application initializer:
#EnableScheduling
#EnableAspectJAutoProxy
#EnableCaching
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
My database config file:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages="org.kemri.wellcome.hie.repositories")
#PropertySource("classpath:application.properties")
public class DatabaseConfig {
#Autowired
private Environment env;
#Autowired
private DataSource dataSource;
#Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory =
new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
// Classpath scanning of #Component, #Service, etc annotated class
entityManagerFactory.setPackagesToScan(
env.getProperty("spring.jpa.hibernate.entitymanager.packagesToScan"));
// Vendor adapter
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(vendorAdapter);
// Hibernate properties
Properties additionalProperties = new Properties();
additionalProperties.put(
"hibernate.dialect",
env.getProperty("spring.jpa.hibernate.dialect"));
additionalProperties.put(
"hibernate.showsql",
env.getProperty("spring.jpa.hibernate.showsql"));
additionalProperties.put(
"hibernate.hbm2ddl.auto",
env.getProperty("spring.jpa.hibernate.hbm2ddl.auto"));
entityManagerFactory.setJpaProperties(additionalProperties);
return entityManagerFactory;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager =
new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManagerFactory.getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
My Thymeleaf config file:
#Configuration
public class ThymeleafConfig {
#Bean
public ServletContextTemplateResolver templateResolver(){
ServletContextTemplateResolver thymeTemplateResolver = new ServletContextTemplateResolver();
thymeTemplateResolver.setPrefix("/WEB-INF/views/");
thymeTemplateResolver.setSuffix(".html");
thymeTemplateResolver.setTemplateMode("HTML5");
return thymeTemplateResolver;
}
#Bean
public SpringSecurityDialect springSecurityDialect(){
SpringSecurityDialect dialect = new SpringSecurityDialect();
return dialect;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addTemplateResolver(templateResolver());
Set<IDialect> dialects = new HashSet<IDialect>();
dialects.add(springSecurityDialect());
engine.setAdditionalDialects(dialects);
return engine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setViewClass(ThymeleafTilesView.class);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
My Web config class:
#Configuration
#PropertySource("classpath:application.properties")
public class WebConfig extends WebMvcAutoConfigurationAdapter {
#Autowired
private Environment env;
#Bean
public JavaMailSenderImpl javaMailSenderImpl() {
JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl();
mailSenderImpl.setHost(env.getProperty("smtp.host"));
mailSenderImpl.setPort(env.getProperty("smtp.port", Integer.class));
mailSenderImpl.setProtocol(env.getProperty("smtp.protocol"));
mailSenderImpl.setUsername(env.getProperty("smtp.username"));
mailSenderImpl.setPassword(env.getProperty("smtp.password"));
Properties javaMailProps = new Properties();
javaMailProps.put("mail.smtp.auth", true);
javaMailProps.put("mail.smtp.starttls.enable", true);
mailSenderImpl.setJavaMailProperties(javaMailProps);
return mailSenderImpl;
}
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
My controller (where there is an error setting up the controller)
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "index.html";
}
}
What might be causing the ConflictingBeanDefinitionException error for my controller class?
I ran into the same problem but for a different reason.
This can also occur if you move your classes around in your project and fail to do a 'clean'.
I use gradle with spring-boot plugin. Now I usually run:
$> ./gradlew clean bootRun
I had the same problem on a Spring integration test when I ran it with InteliJ.
After a refactor, one of my controller class was actually duplicate in the /out/production/classes directory which is the default output directory for Intelij since version 2017.2.
Since the gradle output directory is different (It's build/classes), the gradle clean goal had no effect.
For me the solution was to manually remove /out/production/classes and re run my integration test.
For a possible durable solution not having 2 output directories see here
The solution, as I found out, is to disable double initialization by including a filter in the component scan. In my case:
#EnableScheduling
#EnableAspectJAutoProxy
#EnableCaching
#Configuration
#ComponentScan(basePackages = { "org.kemri.wellcome.hie" },
excludeFilters = {#Filter(value = Controller.class, type = FilterType.ANNOTATION)})
#EnableAutoConfiguration
#PropertySource("classpath:application.properties")
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I encountered this with mvn after changing several folder names and related package names. Than I applied maven clean and run spring boot again, all solved:
mvn clean
mvn spring-boot:run
It seems you have two entityManagerFactory, one you will autowire and one you resolve programmatically as Bean:
#Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}
I think you just need your configured Factory in entityManagerFactory() method.
I was having the same problem with a generated .war file from spring-boot. the approved solution (Timothy Tuti's own solution) didn't quite work for me exactly as-is, but I tweaked it a little bit and it worked. I just added the following line to my Application.java:
#ComponentScan(basePackages = { "com.mypackage" })
For reference, here goes my full Application.java
package com.inmoment.devchallenge;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
#SpringBootApplication
#Configuration
#ComponentScan(basePackages = { "com.inmoment.devchallenge.controller" })
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
#Configuration
#EnableNeo4jRepositories(basePackages = "com.inmoment.devchallenge.repository")
static class ApplicationConfig extends Neo4jConfiguration {
public ApplicationConfig() {
setBasePackage("com.inmoment.devchallenge.repository");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("accessingdataneo4j.db");
}
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
I solved my problem by adding a bean name on top of the class.
#Component("myBeanName1")
public class MyBean {
}
And initialize it with #Autowire in this way:
#Autowire
#Qualifier("myBeanName1")
MyBean myBean;
let's assume your package name - com.example.company and the class name is RestExceptionHandler. Then you need to add the full name with the package to be identical.
add annotation #Component("com.example.company.RestExceptionHandler")
It will identify your class without conflict.
I ran into same problem when one of dependencies(say module Y) of current module(say X) also had definition of same class. So I had to create a separate module(say Z) to store common classes and then add dependency on Z for both X and Y to use.

Categories

Resources