I'd like to define some commonly used or generic service classes that should be used/shared by different projects. These common services should already make use of #Transactional, #Autowired and other Spring related stuff. So, I somehow have to define a spring context for these services to work.
Is it possible to put these services in a single external jar library that can then be used/imported by other (child)-projects? How could I create such a "personal framework"?
What you could do is create a maven (or gradle) module that contains the code you desire to be reusable and also have a spring configuration (either XML or Java Config) that will be imported by the project that uses the module (either with or having component scanning pick up the #Configuration class of the module).
Related
I created a Spring Boot Java library which has a set of utilities that perform certain functions. This library can then be used across multiple applications that require its utilities. This library was designed as a Spring Boot application to allow these utilities to be injected in the application context.
Now I wish to execute a JUnit test on one of the utilities to ensure it is working correctly. However, since this application is basically a collection of utilities and not a stand-alone application, it does not have a main class or the main method annotated with #SpringBootApplication. Now, when I run the JUnit test, it comes up with an error.
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...)
Is it possible to test this Java library, or should we write the test cases only in the application that will be using this library?
I think there is some contradiction in what you say:
Created a Library...that was designed as a Spring Boot Application.
Library can be used across multiple applications that require its utilities.
If you implement "1" then there is a module with spring boot maven/gradle plugin configured to create a JAR of the application which is a library.
But if you have, say, module X that wishes to use your library, its impossible to add the dependency on your library in this module, spring boot JAR artifacts are not JARs in a Java Sense... So this won't work in both IDE and maven (I mean technically you'll have compilation errors).
Then you write something that completely makes sense: You say that the library by itself doesn't have a main class/#SpringBootApplication annotated class. From this I conclude that its not a spring boot application, but rather a spring boot starter module.
In this case you should not use #SpringBootTest annotation since it mimics the way of starting up the spring boot application (finds main class, scans the packages according to the package structure, loads the configurations and so forth). You don't need all this. Well, maybe technically you can still create a main class annotated with #SpringBootApplication and put it into src/test/java/.../ in a relevant package, but it doesn't really makes sense.
So basically you have two choices:
You can test the utilities without spring at all as if the utility is just a Java class, mock the dependency with Mockito and you're good to go. Since these tests are fast, it you be the best option.
You can run the integartion test by means of loading the spring context with all the required beans created by the application.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {MyLibraryConfiguration.class})
public class SampleLibraryTest {
#Autowired
private SomeBeanFromTheLibrary theBean;
#Test
public void testFoo() {
....
}
}
Now although you can use component scanning (in this case you'll need slightly different annotations), in the example I've assumed that you're using java config, register all the beans of the library there and create a spring.factories that uses this Java Configuration file to create an autoconfiguration (you add a dependency on the library in module X and it loads the beans defined in the library automatically).
This #ExtendsWith (#RunWith for junit 4) has nothing to do with Spring Boot, it behaves as a "plain" spring, you can autowire beans, create mock beans, there is caching of configurations, etc.
I am working on 2 projects, one web app (Spring MVC) and one standalone backend service application (Spring boot) that heavily interact together. I am using hibernate for both and they are both coded using the Netbeans IDE.
My "issue" is that i end up with duplicate code in both project, mainly in the Repository and Service layers. My entities are obviously also duplicated since both projects use the same database.
Is there a way to make some sort of class library (a third project maybe?) and put all the common code in there? If that is indeed possible, how do you then change each project so they can still access this code as if it were part of them? I was thinking of putting all my Repositories, Services and entities in there to avoid code duplication and greatly reduce the risk of error.
Thank you!
Separate those Repository and Service classes to a submodule.
The structure looks like:
-- your app
-- api (dependent on `common` module)
-- webapp (dependent on `common` module)
-- common
Then the problem is to initialize beans inside common module. AFAIK, you have two options:
In #Configuration class of api or webapp module, add base packages of common module to component scan packages
In api or webapp resources folder, add Spring configuration factory
/src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=your.path.AutoConfiguration
Define service/repository #Bean inside AutoConfiguration class
I am assuming in this answer your projects are connected to each other
You can set multiple properties within one Spring project, where you store your database connection parameters etc. with the help of multiple property files.
For example:
application-web.properties
application-backend.properties
You can use these in your project, by activating the needed properties file per application. The profile names will be web and backend in these cases.
When using maven, this is the command line I am using:
mvn spring-boot:run -Drun.profiles=<<profile>>
Now, back to your java code.
If there are classes only one of your application is using, you can specify this by 'profile'. Example:
#Controller
#Profile({ "web" })
public class WebEndpoint {
}
This way you can make the shared code available for both applications, without duplicating most of the code.
My spring mvc application is broken into modules.
My services are in their own module.
Previously I used to put a #Service annotation on my services, but since they are in a seperate module, that doesn't have spring, how can I wire them up automatically like before in my web application?
If you split application into modules you have split its dependencies too.
For example:
Your ui depends on spring-mvc.
Your services depend on spring-core and hibernate-annotation.
Your services-impl depend on hibernate-core.
And then if your modeles have appropriate dependence. You can use #Service as you used.
Please bear in mind that when you create WAR with your application, all required modules will be placed in WEB-INF/lib along with Spring dependencies (required by MVC module).
So module in which your services are placed may have dependency to spring-context (containing annotations) since the MVC module requires this dependency itself so it will be placed in the final package anyway. If you use maven, it will handle everything under the hood automatically.
However, if you don't want to have dependencies to spring, because, for example, your 'services module' is deployed as a separate, spring-free bundle, you can use JSR330 #Inject, #Resource and #Qualifier Java annotations - these works interchangeable to Spring equivalents. However I don't know Java equivalents of #Service, #Component or #Repository, so in these cases you can rely on XML Spring context configuration in your MVC module.
I'm new to Spring and got a situation that single project with multiple modules including one web module. Web module uses Spring MVC, but I was wondering if I can have main Spring configuration at project level that takes care of whole project, so that I can take full advantages of Spring framework.
main
-module1
-module2
-web
+spring3.1, spring-security
What would be the best setting for this case?
We have this kind of architecture where I work. We decided to use the ContextLoaderListener (Spring Event Listener) in the web module.
Then, in the serverApplicationContext.xml, we import all the modules context files :
<import resource="classpath*:module1ApplicationContext.xml" />
<import resource="classpath*:module2ApplicationContext.xml" />
...
Thus you leverage the spring context loading during the web application context initialization.
The build layout and runtime CLASSPATH are two different things. Even if you define separate applicationContext.xml files or #Configuration classes in different modules, they might get merged into a single CLASSPATH.
That being said module1 and module2 might declare their own contexts, but since the CLASSPATH is merged at runtime, only a single main context will be created. Also if you choose to use CLASSPATH scanning in one module, it might pick-up classes (beans) annotated with #Service in other modules.
In web module, which should also have dependencies on Spring core libraries, will also depend on spring-web, MVC and spring-security. This module will create child web context, that has access to main context but not the other way around.
Obviously you should have only a single copy of each library in your uber-JAR (ear?)
i have a maven project having two modules; one spring module and one for gwt module. gwt module depends to spring module. And i have XService interfaces and XServiceImpl implementations as Spring beans annotated as #Service("myXServiceImpl").
I want to call myXServiceImpl bean's method from gwt client-side. For this purpose i write proper gwt classes; XGWTService, XGWTServiceAsync, XGWTServiceImpl and XGWTServiceImpl uses XService by #Autowired (I use spring4gwt and XGWTServiceImpl is a spring bean annotated as #Service("myXGWTServiceImpl"))
Actually, i want a practical solution as simple as defining only XGWTServiceAsync which is annotated with #RemoteServiceRelativePath("spring4gwt/myXServiceImpl")
I wonder if there is an easy way to call my spring beans without coding extra 3 classes(XGWTService, XGWTServiceAsync, XGWTServiceImpl)?
Thanks in advance
Put the XService interface and all the classes used by it in a separate package. Make the XService extend RemoteService. You can then define a GWT module that includes those classes. Package the source along with the jar file. Inherit the GWT module in your main GWT module and implement only the XServiceAsync interface.
You can also do away with manually implementing the XServiceAsync - the maven GWT plugin has an option to generate the Async version from the interface.
The only awkward thing in this is making the XService implement the RemoteService interface of GWT and thus having to make your service implementation depend on the GWT jar. But since it doesn't come in the way of implementation that is something that we can live with.
The other option is to just create a XGwtService interface that extends XService & RemoteService - not add any additional methods into this. On the server just the XServiceImpl should be sufficient.