Anton
Anton

Reputation: 120

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.

Upvotes: 7

Views: 26734

Answers (5)

Mahesh Bhuva
Mahesh Bhuva

Reputation: 764

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

Upvotes: 1

Mark Bramnik
Mark Bramnik

Reputation: 42431

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
}

Upvotes: 6

Nikolas
Nikolas

Reputation: 44368

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
}

Upvotes: 9

Chintamani
Chintamani

Reputation: 1166

You can use excludeFilter annotations provided by spring boot .

Upvotes: 1

Martin Frey
Martin Frey

Reputation: 10075

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.

Upvotes: 0

Related Questions