Spring bean not getting Autowired from custom library - spring

I have created by own library(com.custom.mylib) which returns a string like below.
#Component
public class MyLibrary{
#Value("${str.message}")
private String message; //This val should come from app which is going to use this lib
public String readMessage() {
return message;
}
I have create a project which is going to use above library. I have included the lib as pom dependency .But when I try to call library method from my app. I get the error below.
How to resolve it?
#Autowired
private MyLibrary myLibrary;
Consider defining a bean of type 'com.custom.mylog.MyLibrary' in your
configuration.
I also have below in application.properties file so that library can pick the value up
str.message=Hello world

I got the solution it seems.I need to create META-INF file and do org.springframework.boot.autoconfigure.EnableAutoConfiguration=<fully_qualified_name_of_configuration_file>
as given here
Spring Boot: autowire beans from library project

As it has to be used as a external library, you can instantiate it throught a #Configuration file:
#Configuration
public class AppConfiguration {
#Bean
public MyLibrary createMyLibraryInstance() {
return new MyLibrary();
}
}
The rule I used is the follow (this is not an universal rule):
In your domain classes (Controller, Service) : use #Autowired in your constructor. It is the recommanded way to inject your dependencies.
You want to use external classes : implements a Java Configuration with #Configuration annotation, to instanciate your external classes as beans.
You want to create custom utilities classes : decorate it with #Component.
When you have more than on implementation, use #Qualifier and define your beans in a #Configuration class.

Related

Can I get another #Configuration only through #ComponentScan

I am using spring-boot 2.0.4; I have a bunch of services and they have a common configuration class marked with #Configuration.
I want to move this to a common dependency which will have this #Configuration, and based on the need, any micro-service can use #ComponentScan to activate this configuration from dependency.
I have done this for #Component classes, and it's working fine. I activate any particular component I need by adding it into #ComponentScan. How can I activate the configuration in a similar manner(based on need).
Here are the code examples:
Common Configuration:
package abc.department.common.configs.mongo
#Component
public class AbcMongo {
#Bean
public MongoTemplate mongoTemplate() {
// ... create MongoTemplate.
return createdMongoTemplate;
}
}
Here is a class which uses the above dependency:
#Configuration
#ComponentScan("abc.department.common.configs.mongo")
public class MyServiceConfigs {
}
Similarly, I want to do something like this:
package abc.department.common.configs.security.web
#Configuration
#EnableWebSecurity
public class AbcWebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// ... do common configs;
}
}
and now, if a service would need web-security config, it could get like:
#Configuration
#ComponentScan({"abc.department.common.configs.mongo","abc.department.common.configs.security.web"})
public class MyServiceConfigs {
}
#Configuration is meant to specify the beans, for example:
#Configuration
public class MyMongoConfiguration {
#Bean
public MongoTemplate mongoTemplate() {
return new ...
}
#Bean
public MySampleBean mySampleBean(MongoTemplate tpl) {
return new MySampleBean(tpl);
}
}
But if so why do you need to work with #Component at all (at least for the beans you create)?
Configuration is a special bean used by Spring framework to load other beans and it can be viewed as a "substitution"/alternative technique to component scanning.
I believe that, if you have some infrastructure configuration that loads a bunch of "infrastructure beans" (shared jar if I get you right), then the services that use this jar should only say "Hey, I want to load this configuration" and not to scan inside the packaging structure of that jar. Why do I think so?
What if you decide to add new beans into a new package in the infra, should external services change their code and define an additional folder to scan? - Probably no.
What if you decide to move the infra to another package?
Now in Spring there are two simple ways to do this that come to mind:
Way 1: Use #Import Annotation
#Configuration // this is from "shared artifact"
class MyInfraConfiguration {
}
#Configuration // this is from an "applicative service" that uses the infra jar in dependencies
#Import(MyInfraConfiguration.class)
class ServiceAConfiguration {
}
Way 2: Use Spring Factories mechanism
The first way has a drawback: You need to know in a Service what infra configuration exactly is. If you see it as a drawback, consider using spring factories.
Spring factories allow registering the infra configuration in some file so that spring boot will load it in service one automatically, you won't even need to mention MyInfraConfiguration in the Service Configuration, just add a dependency to the infra jar and it will work.
In the infra component create:
META-INF/spring.factories
And add there:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycompany.myinfra.whatever.InfraConfiguration
That's it.
Now if you want to customize the loading of beans in the infra configuration, like, a creation of Mongo related templates only if some properties are available, you might want to use #Conditional. Now, although this is kind of out of scope for this question, I mention this because in conjunction with spring factories this can create a very flexible way to manage your configurations

Dynamic autowire in /src/groovy

I want to be able to include Services in my Groovy Classes in /src/groovy
I found a solution with :
myBean(MyBean) { bean ->
bean.autowire = 'byName'
}
But I dont want to make this entry in the resources.groovy for all Class, so is there a Solution to Autowire all classes in a specific folder?
I'm using grails 2.4.3
This seems to be similar to this question: Grails 2.x service injection in Groovy/src
What we use and is proposed there is to get the service via the application context:
import grails.util.Holders
...
def myService = Holders.grailsApplication.mainContext.getBean 'myService'
It's not completely auto-wired, but seems to be the best way to get services into src/groovy.
Edit: also works for Grails 3
You can make a class com.example.MyClass in src/groovy a Spring bean by adding the following to BuildConfig.groovy
grails.spring.bean.packages = ['com.example']
and annotating the class with #Component, e.g.
#Component
class MyClass {
#Value('${conf.apiVersion}')
String apiVersion
#Autowired
SomeService someService
}
As shown above, you can dependency-inject the class with the usual Spring annotations such as #Value and #Autowired. I find this a much more convenient way to register a Spring bean than modifying resources.groovy.

How to dynamically register the bean specific properties on bean initialization

I want to register the bean specific properties on bean creation if not exists in the application. For example
public class BeanOne {
#Value("${prop1}")
private String property1;
}
public class BeanTwo {
#Value("${prop2}")
private String property2;
}
I want to register the property 'prop1' and 'prop2' to instantiate the above two beans successfully.
My application is configured with spring-cloud-consul-config. By default consul is not configured with these properties in that time, application will automatically register these properties into consul through ecwid/consul-api
Currently the application throws "IllegalArgumentException" with message "Could not resolve placeholder 'prop1' in string value "${prop1}"
Any Suggestions to avoid the above error.
There are various ways you can do this.
My preferred approach is to set the properties in one or more files externally and then use the #PropertySource("file:///full-path-to-property-file") annotation in a #Configuration class.
This approach, combined with Spring Profiles is very powerful.
Example if you are not using profiles:
Create an application.properties file somewhere on your PC. A good
place to put this is ${user.home}/.somefolder/application.properties
Add the values for prop1 and prop2
Change the permissions on that folder and file. For example you can
run chmod u on .somefolder and chmod 600 on the properties file
Create a Spring Java Configuration class and annotate it with
#Configuration. For example you can create an ApplicationConfig
class in a sub package of your Spring Boot application and annotate
it with #Configuration
Add the #PropertySource annotations as follows:
#PropertySource("file:///${user.home}/.somefolder/application.properties")
An example from my course on Spring Boot, AWS, Bootstrap and Stripe:
#Configuration
#EnableJpaRepositories(basePackages = "com.devopsbuddy.backend.persistence.repositories")
#EntityScan(basePackages = "com.devopsbuddy.backend.persistence.domain.backend")
#EnableTransactionManagement
#PropertySource("file:///${user.home}/.devopsbuddy/application-common.properties")
public class ApplicationConfig {
}
That's it!

Is constructor injection possible in Spring configuration classes?

If I have a Spring configuration class (i.e. a class annotated with #Configuration) can I use constructor injection ?
As it stands if I add one I get a no default constructor message, and if I add a default constructor it uses that rather than the overloaded one, which doesn't really help.
There is a bug report about this limitation. It will be fixed with Spring 4.3.
Please note that another bug report (not fixed yet today fixed in 4.3-RC1) report a problem when using this very new feature and injecting generics in constructor of a #Configuration class.
In Spring 4.3, you can use org.springframework.beans.factory.ObjectProvider in #Configuration annotated class constructors to inject beans. for example:
#Configuration
public class SimpleBean {
private final InnerBean prop1;
public Simple Bean(ObjectProvider<InnerBean> innerBeanProvider) {
prop1 = innerBeanProvider.getObject();
}
}

Possible to autowire imported utility classes in Spring?

I want to use data mappers, logger, transfromers, etc. in my Spring web projects. Is it possible to autowire an imported (jar) utility dependency, without wrapping it in some #Component or #Service class? Do we even want to do it that way, or should we just use a static reference?
If your utils, are based on not static methods, then this is simple:
If you use java based configuration, then just declare that util in an #Bean annotated method.
#Configuration
public class YourConfig {
#Bean
public YourUtil util(){
return new YourUtil ();
}
}
in xml it could been as simple as:
<bean id="util" class="org.example.YourUtil" />
The following is true, but it is not what was asked for:
There are at least two other ways to inject beans in instances that are not created (managed) by Spring:
(1) add #Configurable annotation to this class - this requires real AspectJ (compile-time or load-time -weaving)
#see Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
#see this answer of mine https://stackoverflow.com/a/7007572/280244 for a quick "guide" to enable the #Configurable support
(2) invoke SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
#see this question and its (two highes voted answers) for some ideas how to use
You can only #Autowire a bean managed by Spring. So you have to declare your instance through some configuration : a bean in an xml file, or a #Bean method in a java configuration.
#Component are just automatically discovered and registered in the spring context.

Resources