How to include multiple #SpringBootApplication by #Profile? - java

I would like to define multiple #SpringBootApplication configurations that should load different packages. So that I can only load certain parts of the application, depending on the -Dspring.profiles.active= property.
Eg, the following MyApp1 startup class should only auto load classes under com.myapp.config1 subpackages:
package com.myapp.config1
#SpringBootApplication
#Profile("app1")
public class MyApp1 {
public static void main(String[] args) {
SpringApplication.run(MyApp1.class, args);
}
}
And another package aside:
package com.myapp.config2
#SpringBootApplication
#Profile("app2")
public class MyApp2 {
public static void main(String[] args) {
SpringApplication.run(MyApp2.class, args);
}
}
Problem: I cannot have multiple main() in multiple classes, as I lateron want to run my app with mvn spring-boot:run. How could this be solved?

If you want to load different packages depending on a profile you should instead define different configuration classes that are annotated with different #ComponentScan annotations.
#Configuration
#ComponentScan("bar.foo")
#Profile("app1")
public class loadApp2 {
}
#Configuration
#ComponentScan("foo.bar")
#Profile("app2")
public class loadApp1 {
}
This is actually the recommended way of setting up configuration and is called "slicing" and is documented in the spring boot docs

If I understand your question properly, then you want to run different class based on profiles, then you can have profile like below:
#Configuration
#ComponentScan("abc")
#Profile("app1")
public class MyApp1 {
//
}
#Configuration
#ComponentScan("xyz")
#Profile("app2")
public class MyApp2 {
//
}
Now in your SpringBootapplication:
#SpringBootApplication
public class SpringApp {
#Autowired
Environment env;
public static void main(String[] args) {
if (Arrays.asList(env.getActiveProfiles()).contains("app1"))
SpringApplication.run(MyApp1.class, args);
else
SpringApplication.run(MyApp2.class, args);
}
}

Could solve it as follows.
package com.myapp
#SpringBootApplication(scanBasePackages = "com.myapp.config")
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Which loads config:
package com.myapp.config
#Configuration
#Profile("app1")
#ComponentScan(basePackages = "com.myapp.app1")
public class App1Config {
//only load classes from app1 package
}
#Configuration
#Profile("app2")
#ComponentScan(basePackages = "com.myapp.app2")
public class App2Config {
//only load classes from app2 package
}

You could specify the main class in the spring boot plugin configuration. I am not sure if you are using gradle or maven... so cant tell you the exact config.
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#goals-repackage-parameters-details-mainClass

Related

How to disable an annotation when running locally? [duplicate]

I have a question, maybe simple, but I can not find out the solution.
I am using spring boot and added some annotation to the code like this:
#EnableEurekaClient
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
But in some other environment, for example, in production environment, we want to remove EurekaClient, but I do not want to manually remove it manually for each environment, instead, I want to use environment variable or command line parameter to control the behavior. I suppose to do this way:
#EnableEurekaClient(Enabled = {EnableEureka})
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Then I can easily start this application without touching the code.
Can anyone tell me if this is possible? If so, how can I do it?
Thanks
You would want to work with Spring Boot Profiles. Split out the #EnableEurekaClient to another #Configuration class and also add an #Profile("eureka-client") to the class. Then when starting up the application you can set a -Dspring.profiles.active=eureka-client for the environments other than production.
Example:
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#Configuration
#EnableEurekaClient
#Profile("eureka-client")
public class EurekaClientConfiguration {
}
I prefer this method as you don't have to create an extra profile:
#Configuration
#EnableEurekaClient
#ConditionalOnProperty(name = "application.enabled", havingValue = "true", matchIfMissing = false)
public class EurekaClientConfiguration {
}

#WebFilter requires ServletComponentScan

Class may be annotated with #WebFilter(urlPatterns="*") but spring does not run it on request. Why? If I add #ServletComponentScan annotation to Application class. It will work fine. Сan somehow make it work in a different way?
#ServletComponentScan
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#ServletComponentScan will fix the problem

How can I use spring-cloud-zookeeper-discovery in cas-overlay-5.1.x

I want to register the CAS as a Microservice to ZK,
there is my setting in application.properties
spring.application.name=aep-casserver
spring.cloud.config.discovery.enabled=true
spring.cloud.zookeeper.discovery.enabled=true
spring.cloud.zookeeper.connect-string=127.0.0.1:2181
spring.cloud.zookeeper.discovery.register=true
spring.cloud.zookeeper.discovery.instance-host=${LOCAL_IP}
spring.cloud.zookeeper.discovery.instance-port=${server.port}
spring.cloud.zookeeper.discovery.instance-id=${spring.application.name}-${spring.cloud.zookeeper.discovery.instance-host}:${spring.cloud.zookeeper.discovery.instance-port}
But no effect when I started the cas in tomcat.
Maybe you can use #EnableDiscoveryClient annotation in your Application Class. Such as:
#SpringBootApplication
#EnableDiscoveryClient
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

Spring boot to load list of packages from properties file

I have project setup using Spring boot that loads individual components on startup. Each individual packages contain its own datasource, processes, etc. I can simply use this and it works fine
#SpringBootApplication(scanBasePackages = {
"com.package1",
"com.package2",
"com.package3"
})
public class Application extends SpringBootServletInitializer{
public static void main(String[] args){
SpringApplication.run(Application.class,args)
}
}
But currently, the number of indiviual projects are getting bigger. Is it possible to put the list of the components / packages to scan in an external properties file or spring vault? I'm not sure how to retrieve it, and is it possible to retrieve the properties before the boot?
Edit:
Currently I tried this:
#Import(AppConfig.class)
public class Application extends SpringBootServletInitializer{
public static void main(String[] args){
SpringApplication.run(Application.class,args)
}
}
#Configuration
#ComponentScan(basePackages = {$app.packages})
#EnableAutoConfiguration
public class AppConfig {
}
//in my properties file
app.packages = ["com.package1","com.package2","com.package3"]
but its not working
You are on right track but couple of minor mistakes, specify the packages by common separated in yml or properties file
app.packages = com.package1,com.package2,com.package3
Then use Spring Expression Language in #ComponentScan annotation
#ComponentScan(basePackages = {"${app.packages}"})
This can be done using a static string constant. I tried following and it is working.
ScanBasePackageTestApplication is in 3rd package other than "test.packageOne, test.packageTwo" packages. Then I tried to autowire single class from each of test.packageOne and test.packageTwo into class from main package and it worked fine.
#Configuration
#SpringBootApplication(scanBasePackages = PackagesScanMetaData.PACKAGES_TO_SCAN)
public class ScanBasePackageTestApplication {
public static void main(String[] args) {
SpringApplication.run(ScanBasePackageTestApplication.class, args);
}
}
public class PackagesScanMetaData {
public static final String PACKAGES_TO_SCAN = "test.packageOne, test.packageTwo";
}
In this case you can manage all the to be scanned package list in PackagesScanMetaData class. Hope this helps.

What can Spring Boot Application classes extend?

I notice that Spring Boot application classes can extend other classes, but that the main(String[] args) methods generally all use SpringApplication.run(Application.class, args). The examples often use different annotations above the Application class definition.
This OP asks for a simple summary of three closely related questions:
1.) What are the possible classes that a Spring Boot Application.java class can extend?
2.) What are the intended uses of each of the extension options?
3.) And does the choice of a given extension also dictate specific annotations that must be added to the class definition?
From my research, I have identified the following three extension options:
1.) Extend nothing at all, as per this example:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.) Extend WebMvcConfigurerAdapter, as per this example:
#SpringBootApplication
#Controller
public class UiApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
}
3.) Extend SpringBootServletInitializer, as per this example:
#Configuration
#EnableAutoConfiguration
#EnableScheduling
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String... args) {
System.setProperty("spring.profiles.default", System.getProperty("spring.profiles.default", "dev"));
final ApplicationContext applicationContext = SpringApplication.run(Application.class, args);
}
}
Notice that I kept the annotations and minimal other stuff from the examples. This OP asks simply if specific annotation choices or minimal other stuff are dictated by the choice of extension.
Another one, which is not inheritance but it's composition, is to implement the CommandLineRunner interface so that you can perform some operations when the Spring Boot application starts up, like so:
#SpringBootApplication
public class DevopsbuddyApplication implements CommandLineRunner {
/** The application logger */
private static final Logger LOG = LoggerFactory.getLogger(DevopsbuddyApplication.class);
#Autowired
private UserService userService;
#Value("${webmaster.username}")
private String webmasterUsername;
#Value("${webmaster.password}")
private String webmasterPassword;
#Value("${webmaster.email}")
private String webmasterEmail;
public static void main(String[] args) {
SpringApplication.run(DevopsbuddyApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
User user = UserUtils.createBasicUser(webmasterUsername, webmasterEmail);
user.setPassword(webmasterPassword);
Set<UserRole> userRoles = new HashSet<>();
userRoles.add(new UserRole(user, new Role(RolesEnum.ADMIN)));
LOG.debug("Creating user with username {}", user.getUsername());
userService.createUser(user, PlansEnum.PRO, userRoles);
LOG.info("User {} created", user.getUsername());
}
}
Not sure if this is what you're looking for though.

Categories

Resources