I'm trying to create a general purpose springboot service in a jar file that can be used across several applications. To do this I have create a jar file (using maven) that has the following:
A set of three classes and one interface in this single jar. They are in their own distinct package:
package com.hmg.generic.service
MyServiceConfig
MyServiceDataSourceConfig
MyService
IMyService
I have a main application in a separate project, that contains
#ComponentScan(basePackages = {"com.hmg.apps.myapplication","com.hmg.generic.service"})
public class MyApplication extends SpringBootServletInitializer {
My question is, how do I annotate the classes, and do I need any kind of factory method, or helper code, to get the classes in the jar to be instantiated and spun up when the application starts?
When I try to spin up the application I get the following message:
Field config in com.hmg.app.myapplication.MyApplication required a single bean, but 2 were found:
- myServiceConfig: defined in file [/Users/tgia/Development/source/MyApp/GenericService/target/classes/com/hmg/generic/service/MyServiceConfig.class]
- com.hmg.generic.service.MyServiceConfig: defined in null
I want it to be a library, that contains a class, that is used like any other service in my application. I don't want to spin it up like a separate application. To included it as one of the parameters on the constructor of the class where it's going to be used.
#Component
public class AccountResource {
AccountResource(IMyService runtime, AccountInfoService accountInfoService,
AppInfo appInfo) {
this.runtime = runtime;
this.accountInfoService = accountInfoService;
this.appInfo = appInfo;
}
Related
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.
I am writing a controller test for a spring boot application. To use the spring application context I am using SpringRunner class. The problem is the main application class has a property source defined to a specific file path.
When I am running the test I am getting a FileNotFound exception from the hardcoded file. I want my test to be independent of this property source.
I cannot add the 'ignoreResourceNotFound' option for property source in the main application.
Below is the main application class with property source defined.
#SpringBootApplication
#PropertySource("file:/opt/system/conf/smto/management.properties")
#EnableConfigurationProperties
public class ManagementApp {
public static void main(String[] args) {
SpringApplication.run(ManagementApp.class, args);
}
}
I am also adding my test class below
#RunWith(SpringRunner.class)
#TestPropertySource(locations = {"classpath:application.properties","classpath:management.properties"})
#DirtiesContext
#EmbeddedKafka(topics = {"management-dev"},partitions = 1,
controlledShutdown = false,brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
#AutoConfigureMockMvc
#WebMvcTest(Controller.class)
public class ControllerTest {
}
I have found a workaround to create the spring context in this scenario. I have changed my testing class package and because of it, the spring-boot test cannot find the primary configuration class. And then provided all the required packages to create the application context.
Reference for this solution found from spring docs here.
Spring Boot’s #*Test annotations will search for your primary configuration automatically whenever you don’t explicitly define one.
The search algorithm works up from the package that contains the test until it finds a #SpringBootApplication or #SpringBootConfiguration annotated class. As long as you’ve structured your code in a sensible way your main configuration is usually found.
I have a Spring Boot application. For a specific package of services i need to provide 2 different implementations (one using db one using HTTP API).
One set should be active by default and the other by setting a profile.
the package structure is:
otherstuff
service
dbimpl
httpimpl
<serviceinterfaces>
dbimpl (all classes in there) should be active by default and httpimpl should be activate by profile (that should deactivate dbimpl classes)
What is the easiest way to implement such an "switch"?
I thought about using #ComponentScan but i don't know how to switch between different Classes with component scan - i don't know how to have multiple classes with #ComponentScan and switch between them by profile.
I also don't want (at the moment worst option) to annotate each class with Profile.
So how to (de)activate complete packages by profile?
Assuming you have something like
package org.example;
#SpringBootApplication
#ComponentScan("org.example")
public class BootApplication {
}
1) Split your configuration into multiple classes and put them into separate nested package, say org.example.config
package org.example.config;
#Profile("default")
#Configuration
#ComponentScan("service.dbimpl")
public class DefaultConfig {
}
and
package org.example.config;
#Profile("!default")
#Configuration
#ComponentScan("service.httpimpl")
public class CustomConfig {
}
Assuming default is the name of default profile. It could be set up in application.properties file
spring.profiles.active=default
2) Replace global component scan in SpringBoot application with a less global one
#SpringBootApplication
#ComponentScan("org.example.config") // instead of "org.example"
public class BootApplication {
}
This should do the trick
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
Following the example here On deploying a sample resource using the Grizzly container.
It uses a resource that is defined as a class, instead I would like to define an interface with the annotations and have the resource class implements that interface.
The problem now is that Grizzly complains that it can't find the resource:
com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
On Main class, where "com.mycompany.pack" is the package containing the implementation class:
final String baseUri = "http://localhost:9999/";
final Map<String, String> initParams = new HashMap<String, String>();
initParams.put("com.sun.jersey.config.property.packages", "com.mycompany.pack");
[Edit]: It works however when adding the annotations on the class as well.
If there is a way to have the annotations declared only at the interface level.
You can't do it with package scanning because that only looks for classes with the JAX-RS annotations on them. You'll have to use a different approach: either one of the configuration options mentioned in the Jersey user guide that lets you explicitly declare your resource classes, or you could also use jersey-spring to manage your instances. With jersey-spring, there are no extra steps to be able to use an interface like you want to. You just annotate the interface, make the implementation a Spring bean, and it works.