Spring Boot multi module project and bean creation order - java

I have a main module named core and other modules that defines Spring beans of type Job.
I'd like to have a List<Job> in my main module.
The problem is that the creation of the #Service class that contains the #Autowired List<Jobs> is happening prior to the creation of the Jobs in the other modules (which are a maven dependency in core).
How can I direct Spring to gather all Jobs into a list in the main module?
I tried to use #Order but it doesn't seem to make any affect.

Try creating Job bean under configuration file.

Related

External jar as Spring application

Let say I have an external jar named data-access-0.0.1.jar that contains Spring annotation like #Component, #Bean. But this jar does NOT contain the main method to run as a Spring application (means no #SpringBootApplication, no #ComponentScan, ...).
Now I have another jar named employee.0.0.1.jar (does have the main method to run as Spring boot application - #SpringBootApplication), that use data-access-0.0.1.jar as a dependency. But somehow it does not scan #Bean, #Component in an external jar (error when starting the app, no bean with type "myComponent" found).
I think #ComponentScan in employee-0.0.1.jar should configure base packages include a package from the external jar and it should work, but I do not want to apply this mechanism. I want to somehow configure in the external jar so that any another jar that depend on it should scan the whole jar for autowiring

Using a Spring Bean from another project - Entity Manager setup.

I understand that the way these projects have been structured isn't necessarily good design, but i have found myself working on a project which has the following format and have a dependency and spring bean configuration issue:
Project A :
Is a Spring Project. Spring configuration is in an XML file. The project consists of many different beans and classes. Some of these classes are Services which make calls to a database(JPA/Hibernate is used). So in the Spring configuration file there is an entityManagerFactory defined, a Datasource etc and all the beans needed to perform database operations.
Project B:
Is also a Spring project, and also contains various beans and classes. This project also contains classes which make calls to a database(using JPA/Hibernate). So the Spring configuration also defined an entityManagerFactory/datasource etc. The project contains a series of Entity Classes which are scanned by the entityManagerFactory using the property 'packagesToScan'. The configuration is using Java Config.
The problem:
A bean in Project A needs to use a bean from Project B. The bean from project B is a Service class which reads data from the database. I want to be able to inject the bean from Project B into the class from Project A. I am using gradle in both projects, so have added Project B into Project A as a gradle dependency.
I tried adding a to the configuration from Project A to scan the package in Project B which contains the Java Config. I thought this would enable me to autowire the class from Project B into Project A. However, i am getting an exception that the entities in Project A are not managed entities and that autowiring is failing. Does this mean i need to scan the entities in Project B with the entityManager in Project A? Does this mean i cannot autowire a bean which has already been configured in the configuration of another project? Do i need to add this bean to Project A xml configuration and do all the property setting there, copied from Project B?

Spring boot configuration in a multi-Module maven project

I'm having a problem properly setting up spring boot for my multi-module maven project.
There is a module "api" that uses another module "core". Api has an application.properties file that contains spring.mail.host=xxx. According to the spring boot documentation this provides you with a default implementation of the JavaMailSender interface, ready to be autowired.
However the class that is responsible for sending out the e-mails resides in the "core" package. When I try to build that module the build fails because no implementation of JavaMailSender can be found.
My guess then was that the mailing config should reside in "core" in a separate application.properties. I created that and moved the spring.mail.host property from the "api" to the "core" property file.
This time the core module builds successfully, but "api" fails to build because of the same exception, so I think I just moved the problem.
I don't understand the required structure for handling this type of situations well enough so I was wondering what the correct way is for having a "core" module containing all the correct configuration for sending mails and having other modules use the mailing code and config that resides in it.
I found the answer in another stack overflow question: How to add multiple application.properties files in spring-boot?
It turns out there can only be 1 application.properties file in the final jar that spring boot creates. To have multiple files you have to rename one of the files to something custom. I named the properties of the core module "core-application.properties".
Then in the API module I added this to the spring boot application class:
#SpringBootApplication
#PropertySource(value = {"core-application.properties", "application.properties"})
Doing this I can correctly use the base properties file and overwrite them in the more specific modules. Also you can still create profile-specific properties file (core-application-production.properties) with this setup, no need to add those to the propertysource manually). Note that #PropertySource does not work for yaml configuration files at this moment.
there is one effective application.properties per project. you just keep 2 properties file for a success build.
when api module use core module, the application.properties in core module is overwrite by api.
Your API's pom.xml must has dependency of CORE module.
the solution is to define properties files as a value of #PropertiesSource in Starter class.
but it is beter to put "classpath:" behind the properties files.
for example in Intellij idea after adding the "classpatch:" word berhind the files name, values become to link. like this:
#SpringBootApplication
#PropertySource(value = {"classpath:core-application.properties", "classpath:application.properties"})
I hope to helped you.

How can I #Autowire a spring bean that was created from an external jar?

I have a module/jar that I've created and am using as a util library. I created a service in there like so:
#Service
public class PermissionsService { ... }
... where this resides in a package here: com.inin.architect.permissions and in my main application, I'm referencing/loading this jar (i.e. set as a dependency in the maven POM.xml file for the app) like so:
<dependency>
<groupId>com.inin.architect</groupId>
<artifactId>permissions</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
and within the application I want to use that service like:
#Autowired
PermissionsService permissions
In the application's spring setup, I've got this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.inin.generator", "com.inin.architect.permissions" })
public class WebConfig extends WebMvcConfigurerAdapter implements ServletContextAware { }
However when I run my application under tomcat, it complains that there isn't a bean for the PermissionsService: "org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ..."
So, how can I bring over the bean from the lib into my application? Surely there's a way. Do you have to set the library up as a full blown spring MVC application so that this can work? i.e. do you have to have #Configuration and #ComponentScan setup in the lib as well?
You have to scan at least the package containing the class you want to inject. For example, with Spring 4 annotation:
#Configuration
#ComponentScan("com.package.where.my.class.is")
class Config {
...
}
It is the same principle for XML configuration.
Just a note on this, but you could decouple your dependency from spring. In your #Configuration class create
#Bean public PermissionsService permissionsService(){
return new PermissionsService()
}
This will also allow it to be injected. Not that you have to remove your spring annotation, just an option making it potentially usable outside of spring.
Ok - i had exactly the same problem - i wanted to autowire a mongo db repository interface from an external jar.
I could autowire every bean from that jar with using
#SpringBootApplication(scanBasePackages = {"com.myrootpackage"})
However - autowiring the interface always failed with "Could not find blablabla..."
But the interface was in the same package as the beans i could import.
It turned out that searching for the mongo db interfaces is NOT taking the scanBasePackages from the #SpringBootApplication into consideration!
It has to be explicitly configured via
#EnableMongoRepositories(basePackages = {"com.myrootpackage"})
Or you could move the main class "up" so the default searching works also for the mongo interfaces. So i understood the problem and found a solution. But i am still a bit unhappy because i need to configure the same lookup path twice. I find it stupid honestly.
I faced the same issue while scanning other classes from other project dependencies, The scanning solution depends on the type of classes you need to scan as follows:
if they are normal #Component, #Service annotations use
#ComponentScan({"com.mypackge1","com.mypackage2"})
If the type of classes are domain objects based on entities use
#EntityScan("com.mypackge1.domain")
If JPA repository classes
#EnableJpaRepositories(basePackages = {"com.mypackage.repository"})
If Redis repository classes use
#EnableRedisRepositories(basePackages = {"com.mypackage.repository"})
Same for Mongo, etc.
You can import application-context.xml for com.inin.architect.permissions in the following manner inside your main application.
<import resource="classpath:/permissionApplicationContext.xml" />
This will enable you to autowire beans from com.inin.architect.permissions that you have defined.

Refining a Spring Bean in a multi-module Maven project?

I am drawing a blank on this for some reason. I have a multi-module Spring/Maven project. In module1 I define a singleton bean called "info" and it works within module1 just fine.
However module2 in this project (which depends on module1) has improvements on property values for the "info" bean. Module2's Spring configuration already includes Module1's configuration. What is the Spring configuration I should use to set properties on the "info" bean defined in this subsequent module?
Since Spring 2.5 there is a PropertyOverrideConfigurer. Maybe that's what you are searching for
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-overrideconfigurer
There is a small example on this page
http://ondra.zizka.cz/stranky/programovani/java/howto-substitutions_in_spring_configuration-tutorial.texy
Create a new "info" bean in module2, configuring it the way specific to the needs of module 2.
You would do something like this in your module 2 configuration:
<import resource="classpath:/META-INF/module1-config.xml"/>
<bean name="info" class="Module1class"/>
This should inject the right "info" into the dependent beans

Categories

Resources