6

I am consuming a spring boot project as jar inside another spring boot application using the maven dependency. I want to do the component scan of jar only if I enable a custom annotation from microservice.

@SpringBootApplication
//@ComponentScan({"com.jwt.security.*"})  To be removed by custom annotation
@MyCustomAnnotation  //If I provide this annotation then the security configuration of the jar should be enabled.
public class MicroserviceApplication1 {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(MicroserviceApplication1.class, args);

    }

}

Please suggest some ideas.

Ravi
  • 195
  • 3
  • 15
  • I would suggest to refactor out the code you would like to share and make a separate project of it...Apart from that sharing code in general in the microservice world is a bad idea...Or if you need the way to go is having a mono repo setup.... – khmarbaise Dec 01 '17 at 16:10
  • How did you end up implementing this? – mad_fox Jan 09 '18 at 20:45

2 Answers2

4

In your library:

@Configuration
@ComponentScan(basePackages = { "com.jwt.security" })
public class MyCustomLibConfig{

}


@Retention(RUNTIME)
@Target(TYPE)
@Import(MyCustomLibConfig.class)
public @interface MyCustomAnnotation{

 @AliasFor(annotation = Import.class, attribute = "value")
           Class<?>[] value() default { MyCustomLibConfig.class };
}

So, in your application you can use the annotation

@SpringBootApplication
@MyCustomAnnotation  //If I provide this annotation then the security configuration 
                       of the jar should be enabled.
public class MicroserviceApplication1 {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(MicroserviceApplication1.class, args);
    }

}
Fabio Formosa
  • 904
  • 8
  • 27
  • How would one go about having the `basePackages` variable? E.g. either specifying a custom value `@MyCustomAnnotation(basePackages = "com.example")` or even better, defaulting to the package of the annotated class. I tried this and it looks like without any further configuration, the base package is taken from the Annotation+Config, not from the annotated class. Do you know if this possible? – knittl May 23 '20 at 10:27
  • @knittl In your case MyCustomAnnotation should have the attribute `basePackages` and shouldn't import `MyCystomLibConfig` but a configBean that implements `ImportBeanDefinitionRegistrar`. The `Registrar` can access to the attributes of CustomAnnotation (as basePackages) and it can programmatically build the `MyCustomLibConfig`. To programmatically set a scan package, I suppose that in your case `MyCustomLibConfig`must implement `WebApplicationInitializer`. You can find an example of use of `ImportBeanDefinitionRegistrar` [here](http://shorturl.at/dnoK9) – Fabio Formosa May 24 '20 at 10:52
  • thanks, but is that the correct link? I get presented a chinese PDF? Maybe you could provide a full answer to [my question](https://stackoverflow.com/questions/61971497/spring-custom-enable-annotation-meta-annotated-with-componentscan)? – knittl May 24 '20 at 11:35
  • Sorry, I pasted a wrong link. Anyway, I've just answered to [your question](https://stackoverflow.com/questions/61971497/spring-custom-enable-annotation-meta-annotated-with-componentscan) – Fabio Formosa May 25 '20 at 23:10
0

You can use @Conditional to define configurations (see an example describe here). Some code from the source

@Configuration
public class MyConfiguration {

  @Bean(name="emailerService")
  @Conditional(WindowsCondition.class)
  public EmailService windowsEmailerService(){
      return new WindowsEmailService();
  }

  @Bean(name="emailerService")
  @Conditional(LinuxCondition.class)
  public EmailService linuxEmailerService(){
    return new LinuxEmailService();
  }
}

and conditional

public class WindowsCondition implements Condition{

  @Override 
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    return context.getEnvironment().getProperty("os.name").contains("Windows");
  }
}

You can use profiles. Just add the @Profile to your config class with scan of desired package.

One more alternative is described here.

@AutoconfigureAfter(B.class)
@ConditionalOnBean(B.class)
public class A123AutoConfiguration { ...}
StanislavL
  • 56,971
  • 9
  • 68
  • 98