1

I have a Spring Boot application that hosts a REST API.

Depending on which files get deployed, I want to be able to have it load additional controllers from what is essentially a "plugin" JAR file.

For example, I'd love to be able to do something like this:

java -jar myapp.jar -Dplugins.directory=/opt/myapp/plugins

Is this possible?

Note: these would not be loaded on the fly; once deployed, the set of plugins will remain fixed. I want one application jar that remains the same in every deployment, and the behavior of the application will be determined by the plugins that are deployed alongside it.

Hugh
  • 1,133
  • 1
  • 12
  • 27
  • 1
    I consider such a thing to be too clever by half. You have to restart the app to load the plugins anyway. There's no reason why you couldn't add them as dependencies to the package. – duffymo May 22 '19 at 18:24
  • Check this out. It may help: https://stackoverflow.com/questions/23427745/how-to-put-a-directory-first-on-the-classpath-with-spring-boot – Simon Martinelli May 22 '19 at 18:33

1 Answers1

0

it may not 100% Satisfy your demand. I have two suggestion.

the easy one. java -jar stackoverflow-1.0-SNAPSHOT.jar --spring.profiles.active=prod and put different value "@Profile" on your controller.

@RestController
@Profile("prod")
public class URLOneController {

@PostMapping(value = "/url", consumes="application/json", produces="application/json")
public ResponseEntity<HttpStatus> insertClaim(@RequestBody String messageBody) {
    return new ResponseEntity<>(HttpStatus.OK);
}

}

second suggestion ,dynamic load beanDefiniton.

@Configuration
@ConditionalOnProperty(name="external.controller.enable",havingValue = "true")
public class ExternalClassDefinitionProcessor  implements 
BeanDefinitionRegistryPostProcessor {

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();


    Class<?> aClass = null;
    try {
        aClass = contextClassLoader.loadClass("com.jin.learn.demo.UrlOneController");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
            .genericBeanDefinition(aClass);

    beanDefinitionBuilder.addPropertyReference("personDao", "personDao");

    BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder
            .getRawBeanDefinition();
    registry.registerBeanDefinition("UrlOneController", 
personManagerBeanDefinition);

}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory 
beanFactory) throws BeansException {

   }
}

package your controller into normal jar(not use spring-boot-maven-plugin )

run your app like this command line

java -Dloader.path="lib/,config/,/home/jin/Desktop/abc/target/abc-1.0-SNAPSHOT.jar" -jar stackoverflow-1.0-SNAPSHOT.jar --external.controller.enable=true

the extra contorller in abc-1.0-SNAPSHOT.jar and your main app is stackoverflow-1.0-SNAPSHOT.jar

tips: stackoverflow-1.0-SNAPSHOT.jar should package zip format .

<plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layout>ZIP</layout>
            </configuration>
        </plugin>
jin
  • 430
  • 2
  • 9