Autowire a Bean from dependent library jar - spring-boot

I have a Spring Boot application (main-app) which users Library jar client-app.jar and mentioned as a dependency in of the application main-app.
Now I want to use #Autowire to inject bean from client-app. For this i have to add #ComponentScan on my main-app application.
But is there a way that i don't have to anything on my main-app by changing code on client-app.

Yes, you can create a sub-package by following the main-app let's say main-app has the following root of package com.example.main-app then on your client-app you should create something like com.example.main-app.client-app then the main application will scan its base package and will look the client-app as well.

Related

Spring JPA multi module project

I am trying to create a Spring multi module project.
Module 1, handles the application startup and basic web MVC services.
Module 2, is for MultiTentanted Jpa
Module 2, runs fines fine as stand alone application, but when I include it as a dependency in module 1, I get the following error, Caused by: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class uk.rteksoft.tenantservices.tenant.model.Role!
I am assuming that I am missing something in a configuration bean somewhere, but haven't been able to find out what I need to do to make this work.
I have a parent pom that contains both module 1 and module 2.
Please say if I need to post any configs or other files.
Thanks
John
You need to scan base package from injected module else spring will not create any bean for injected module and you will face dependency errors.
Use scanBasePackages value in SpringBootApplication annotation in main application (you can scan array of packages based on your requirement)
ex:
#SpringBootApplication(scanBasePackages = "com.example.multimodule")
Here is example link of sample app based on multiple
ComponentScan is another way to scan multimodule packages;
#ComponentScan(value = "com.example.multimodule")
also Use below annotations for scan your entities and repositories
#EntityScan("your entity base packages")
#EnableJpaRepositories("your repositories base packages")

Spring AOP aspect doesn't get applied if included from an external jar with different package name

I have a spring boot rest service that included an external project in pom as it's dependency. That external project is basically a jar that has spring AOP code.
The base package in my main application that includes this external jar with spring AOP code is x.y.z
The class in external jar where the #before advice is, is under the package a.b.c
With this class under a.b.c package, it doesn't get recognized by the main application where I want to use the spring aop implementation and apply the aspect. However, when I change it's package from a.b.c to x.y.z (which I really can't do in real life) it works fine.
I know that in spring boot service which happens to be the including service, it scans everything under root package given in the application class, x.y.z in this case and that is why aspect works fine if it's class is under x.y.z.
however, the problem is that this spring app jar will be used across multiple applications. So changing package name like this is not an option.
Is there a way to accomplish this without changing the package name of the class where spring app code is ?
Probably component scan is only activated for your application class packages by default. You can extend it to multiple packages, including the aspect package:
XML style configuration:
<context:component-scan base-package="x.y.z, a.b.c" />
Annotation style configuration:
#ComponentScan(basePackages = {"x.y.z", "a.b.c"})
Disclaimer: I am not a Spring user, only an AspectJ expert. I just knew that you can configure component scan, googled the syntax for you and hope it is correct.
Please define the bean (of jar project )inside main application. Give the #ComponentScan(basePackages = {"x.y.z", "a.b.c"}) as well as #EnableAspectJAutoProxy. Also include below piece of code.
ex:
` #Bean
public LoggingHandler loggingHandler()
{
return new LoggingHandler();
}`
Also annotate external jar code with:
`#Aspect
#Component
public class LoggingHandler {`
What #kriegaex suggests is correct. In addition to that, please make sure you are using #Component along with #Aspect. Since #Aspect is not a Spring annotation, Spring won't recognize it and hence your aspect won't be registered. So, using #Component is mandatory to getting aspects to work in Spring environment.

Wiring a bean from dependency module

I have created a configuration project which essentially creates couple of beans with configuration stereotype. Then, I want this project to be reused across by my clients.
I have added this config project as a maven dependency, but my client project is not having those beans i have created as part of configuration project.
Could someone help
Ok, the answer is the following: you should place
#ComponentScan("you.configurations.base.package")
on one of your configuration (in the current application, one that #SpringBootApplication sees) or on the class with #SpringBootApplication annotation.
The explanation is as follows: #SpringBootApplication under the hood contains #ComponentScan without specifying a base package. That means that it says to Spring to scan the package where the class annotated with #SpringBootApplication resides and all the packages recursively. And that's it. If you place you #Configuration somewhere there - it will create it during startup, otherwise not.
We can resolve this by enabling spring-boot autoconfiguration
Create classpath->resources->META-INF->spring.factories file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=[add your class with you need to be loaded during application load time]

Import by name in Spring Java configs

Say I have 3 Spring/Maven projects:
api-spec: Contains interface MyService.
api-impl: Contains class MyServiceImpl which implements MyService. Also contains class MyServiceConfiguration which is a Spring #Configuration, that defines a bean of type MyServiceImpl.
main: Contains a Spring application setup with Spring JavaConfig (e.g. a #SpringBootApplication). It has a bean with an #Autowired MyService myService field, which works as its configuration class is annotated with #Import(MyServiceConfiguration.class).
I would like the main-project to have api-spec as a Maven compile dependency and to have api-impl as a runtime dependency (to prevent us from making "hard" dependencies from the main project to the api-impl project by mistake). This is not possible, because #Import takes an array of Classes - e.g.: #Import(MyServiceConfiguration.class). I would like something like #Import("my.package.MyServiceConfiguration") instead.
Using class path scanning is not an option (we have seen too many beans getting picked up by accident), and I would prefer not having to use XML files. We could use SpringApplicationBuilder.source(..) as it accepts a class name as a String - but I can't find a way to use that in my tests...
Compile time check is one of the advantages of java config, so I don't think that it's possible to do such thinks with Java. As for me you should use XML to handle this. It doesn't mean that you should do all your configuration in XML, most of the beans of your api-impl module can be in Java and just imported to XML where will be only beans that you are going to change in runtime.
If you don't want to use XML maybe you should consider to use Groovy config instead:
https://spring.io/blog/2014/03/03/groovy-bean-configuration-in-spring-framework-4

Create auto configure spring library to spring-boot application

I am creating a library which uses spring 4.3.0.One of the spring-boot application will consume this library. Currently i am using #ComponentScan in the main class of spring-boot application to scan the beans inside library instead i want to auto-configure it.So what i did is i created a configuration class inside the library and declared #ComponentScan in the configuration file.
After consuming the library in spring-boot application it is not scanning the beans inside library and throws,
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sample.book.client.service.BookService] found for dependency [com.sample.book.client.service.BookService]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1406)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1057)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
... 33 common frames omitted
How to resolve this error ? Why Spring scanning #service classes before #Configuration?
Your help should be appreciable and i will provide code-samples if needed.
It seems to me that most probable cause is that your library resides in a different package than your spring boot application (and its sub-packages). When annotating a class with #SpringBootApplication you also get #ComponentScan annotation set to its default (that is scanning components in a package where a given class resides).
Personally, I prefer to create a #Configuration annotated class in my library projects. Such class is responsible for proper library setup (declaring component scan and so on). Later, in dependent project I use an #Import annotation to import that configuration class (and corresponding beans).
I like the import. But I wanted to avoid any imports or package scan in client code.
I built my-lib (spring-boot)
by defining, Configuration in resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.fanniemae.ebrms.dsrunner.DecisionServiceRunnerConfiguration
added componentScan in my configuration (my-lib)
#Configuration
#EnableConfigurationProperties(DecisionServiceRunnerProperties.class)
#ComponentScan(basePackages = { "com.xyz.dsrunner.*" })
public class DecisionServiceRunnerConfiguration {
and just included as dependency in my client spring boot application.
I guess that your config is not loaded by default from your Boot Application.
I also guess that you have not added
#EnableAutoConfiguration
to your Boot Application.
So you can try to add your config to the Annotation #EnableAutoConfiguration to be loaded by your application. Then the Configuration that you put in META-INF/spring.factories inside your library-JAR is automatically loaded.
Or you can #Import your configuration in your #SpringBootApplication class
#Import({MailServiceConfig.class, ServiceConfig.class})
can be use for enable the specific configurations;
http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html

Resources