简体   繁体   中英

How can I disable creating bean with @Component annotation in Spring?

I have some common interface for refactoring logic in my project. It looks about like this:

public interface RefactorAwareEntryPoint {

    default boolean doRefactor() {
        if (EventLogService.wasEvent(getEventType())) {
            return true;
        }
        boolean result = doRefactorInternal();
        if (result) {
            EventLogService.registerEvent(eventType);
        }
        return result;
    }

    String getEventType();
    
    boolean doRefactorInternal();
}

And than, when I need to write some refactoring - I implement this interface with methods, mark class like @Component , and Spring in loop evaluate each interface implementation and register it in database. But we have a lot of refactors (every year - 200-300 new). It's hard to disable old implementations manualy, and we have a lot of beans in our spring-context. Can we do something, for example, use some annotation - which will disable component creation by some condition?

For example:

@Component
@Enabled(YEAR.2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
 // Code implementation
}

And this annotation will work like this (a pseudocode):

if (YEAR.2020) {
  create bean -> new CustomRefactor()
}

And when it will be YEAR.2021 - we will have no beans from YEAR.2020 in spring-context.

Use the annotation @Profile that makes application configuration and beans available in certain environments.

You can find more at Spring Boot 2.4.0 reference documentation: 3. Profiles

Spring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments. Any @Component, @Configuration or @ConfigurationProperties can be marked with @Profile to limit when it is loaded

Consider each year as a separate environment.

@Component
@Profile("2020")
public class CustomRefactor2020 implements RefactorAwareEntryPoint {
 // Code implementation
}
@Component
@Profile("2021")
public class CustomRefactor2021 implements RefactorAwareEntryPoint {
 // Code implementation
}

In addition to the answers provided by our colleagues, consider the feature of spring called "Stereotype annotations". This is how well-known annotations like @Service are defined in spring.

In general, the fact that you mark your class with @Component annotation allows you to load the class as a spring bean because the annotated class becomes a subject to a process called "component scanning" - a process happens when you start the application context.

Since spring 4 there is a conditional interface that basically makes possible implementing a logic similar to what you refer to as @Enabled(YEAR.2020) .

You might use a built-in "@ConditionalOnProperty" to map the 2020 year to property or even implement a custom conditional logic . I'll assume that you've implemented a custom conditional as @ConditionalOnYear

Now, what's interesting (and this is a "stereotype" feature that I've mentioned at the beginning of the post) is that you may create your own "component" annotation with a custom "conditional" logic and use it "as if" its a regular bean:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConditionalOnYear(2020)
@Component
public @interface Year2020OnlyComponent {

    @AliasFor(annotation = Component.class)
    String value() default "";

}
@Year2020OnlyComponent
public class CustomRefactor implements RefactorAwareEntryPoint {
 // Code implementation
}

You can also improve that by clever usage of @AliasFor annotation to be something like:

@SinceYearComponent(2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
 // Code implementation
}

But this is kind of out of scope for this question - so I just mention a direction here.

Of course, it's possible to merely use two annotations as you've suggested even without this "Stereotype" annotation feature:

@Component
@SinceYear(2020) // a custom conditional
public class CustomRefactor implements RefactorAwareEntryPoint {
 // Code implementation
}

Check out the BeanFactoryPostprocessor interface. Probably you can remove a bean before it's creation.

Else you might implement your own BeanFactory and create the ApplicationContext with your implementation.

您可以使用 spring boot 提供的 excludeFilter 注释。

  1. As mentioned by others you can always use @Profile annotation to enable/disable profiles.
  2. Another option is excludeFilter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM