Sort Intro to Spring Circular Dependency Error
As you probably are aware Circular Dependency occurs, when, for instance, a class A depends on the B class, and the B Class depends on the A class. Generally speaking, this could be a sign of a not well-organized code and probably indicates your classes don’t follow the Single Responsibility Principle. But in Spring, there are cases, where mutual dependencies are a common practice. Such a case is the one that we will see here. This is actually the case when an auto-created bean (e.g.: an AuthenticationManager instance in a @Configuration annotated class) is required in a @Component annotated class (e.g.: a custom filter extending the UsernamePasswordAuthenticationFilter filter), and then, the bean of the @Component custom filter class is required in the @Configuration class.
The case study
In my previous post(s), I have referenced the widely used UsernamePasswordAuthenticationFilter filter, and also, I have described in more detail how you can define and use your own Custom UsernamePasswordAuthenticationFilter filter.
Here we are going to see how we can avoid some Circular dependency pitfalls when we want to annotate it with the @Component annotation for using it as a Spring-managed bean.
How to add a custom security filter
Generally, we have to add our custom security filter, to the SecurityFilterChain. Actually, a custom filter should be added to the HttpSecurity (http) configuration. The HttpSecurity should be configured in a SecurityFilterChain bean inside a @Configuration and @EnableWebSecurity annotated configuration class. As you probably are aware HttpSecurity allows us to configure web-based security for specific http requests. In order to add a custom filter to the HttpSecurity configuration, by using the .addfilter(<filterName>). Also note, that such a custom filter must be an instance of (or extend one) of the Filters provided within the Security framework. This is OK for our case here, since our custom filter extends the UsernamePasswordAuthenticationFilter filter.
The common approach
As we have said, our custom filer is actually a custom filter extending the UsernamePasswordAuthenticationFilter. In most of the implementations, such a custom filter is used initially as a non-bean class, (without using the @Compnent annotation on the class of our custom filter). This is OK because we instantiate and configure it in a private method inside a custom configuration class. In the majority of the cases, this is a custom security configuration class (a class annotated with both @Configuration and @EnableWebSecurity annotations).
In order to instantiate (and before adding it to the SecurityFilterChain) we must pass in it the AuthenticationManager object. Of course, we can use setters for configuring other settings of it. Finally, we add it to the HttpSecurity configuration in the SecurityFilterChain bean.
Annotating our classes as @Components (or making them beans inside a @Configurartion class) is the common Spring approach, and allows us to benefit from injecting/autowiring directly into them, of other beans, as required dependencies, and of all other Spring-managed goodies such as externally defined values (for properties and messages). And this is what we want to do here. We want to make our CustomRequestHeaderTokenFilter a Spring-managed bean.
The demo repo
For our demo purposes here, we will use the outcome (final) repo of the aforementioned post, which you can also find here. Actually, we are going to focus on the following 2 classes:
The CustomSecurityConfiguration, which is our main security configuration class, and the CustomRequestHeaderTokenFilter, which is actually our customized filter extending the “weird” UsernamePasswordAuthenticationFilter. For your convenience, below you can find both of them:
Note that in the CustomSecurityConfiguration class, we use a slightly updated version (comparing it to the repo respective file) of the filterChain1() method (SecurityFilterChain), using the preferred Lambda DSL syntax of the ‘HttpSecurity’.
As you can see, both of them do what exactly we have described above. Now, let’s start making our CustomRequestHeaderTokenFilter, a Spring-managed bean.
Making our custom filter, a Spring-managed bean
We can easily make our CustomRequestHeaderTokenFilter a Spring-managed bean, using the @Bean annotation in our CustomSecurityConfiguration class, as we can typically do with any of our “non-bean” classes. Below, is how you can do that, by simply changing the private customFilter() method, to a public bean class:
This is OK and works fine. But what if we want to make our CustomRequestHeaderTokenFilter a Spring-managed bean, annotating it directly with the @Component annotation?
The problem is that we cannot simply add the @Component annotation and make it a Spring-managed bean.
The main cause is that we use a class constructor that is being used to pass to the super (parent) class an instantiated object of the AuthenticationManager.
One might expect that the Spring autowiring mechanism could have been able to automatically inject an instantiated AuthenticationManager object into the class constructor since the class constructor is the only existing constructor here (@Autowired is not necessary from Spring version 4.3 afterward).
If we try to do so, we probably don’t get a compile-time error, but our custom filter is not being instantiated. Instead of it, the default UsernamePasswordAuthenticationFilter has been instantiated and the default Spring security configuration was set up. Our custom filter fails to be added to SecurityFilterchain, since upon its instantiation, the default UsernamePasswordAuthenticationFilter takes over and is added to the SecurityFilterchain.
This happens because, as we’ve said, our custom filter extends the parent UsernamePasswordAuthenticationFilter. All of the constructors of the parent UsernamePasswordAuthenticationFilter class require an instance of an AuthenticationManager to be provided. However, in our case, such an instance is not available when the Spring mechanism initially instantiates the component bean of our custom filter class. This is because the AuthenticationManager is instantiated as a bean automatically by Spring. It is available via the AuthenticationConfiguration in the CustomSecurityConfiguration, but when our CustomRequestHeaderTokenFilter is instantiated as a bean via the @Component annotation, the AuthenticationManager object is not available yet.
Our case of the Cyclic Dependency Error
A first thought for taking some action could be to remove the class constructor and use a specific setter for the AuthenticationManager -in the CustomRequestHeaderTokenFilter. And then -in the CustomSecurityConfiguration- we can autowire our CustomRequestHeaderTokenFilter (which is now @Component ) and change the customFilter() method, accordingly. E.g.:
In the CustomRequestHeaderTokenFilter:
In the CustomSecurityConfiguration:
However, when we try to start our application, it fails to run, and what we get is the “famous” Cyclic Dependency Error:
*************************** APPLICATION FAILED TO START *************************** Description: The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | customRequestHeaderTokenFilter ↑ ↓ | customSecurityConfiguration (field private com.zzpzaf.restapidemo.Configuration.CustomRequestHeaderTokenFilter com.zzpzaf.restapidemo.Configuration.CustomSecurityConfiguration.authFilter) └─────┘ Action: Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
We have 2 bean classes. A custom filter was annotated via @Component and a Security configuration class was annotated via @Configuration (and @EnableWebSecurity btw). The custom filter extends the UsernamePasswordAuthenticationFilter.
In the configuration class, we define an AuthenticationManager Bean because it is necessary to be @Autowired in a setter method of the custom filter. Furthermore, in the configuration class, we need the custom filter because we want to pass it (add it) in the HttpSecurity filter chain. So, we have defined an @Autowired field for that custom filter.
When the application starts, the Spring mechanism tries to instantiate both of the beans the configuration class and the custom filter. When it tries to instantiate the configuration class, it needs a custom filter bean and then tries to instantiate it. But the, the instantiation of the custom filter, requires the AuthenticationManager bean define in the configuration class, which is still “under instantiation”, and thus the application fails to start.
Note that, as we have said, the AuthenticationManager bean is necessary to our custom filter, because it has to pass it, into the parent class (UsernamePasswordAuthenticationFilter) constructor, otherwise it cannot be instantiated.
Solution 1 – Use the @Lazy annotation
An easily implemented solution is to use the @Lazy annotation. It can be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean. The @Lazy annotation can also be placed on injection points marked with @Autowired (or @Inject).
Spring, by default, initializes eagerly, the beans annotated by a @Component or a @Bean annotation. In the case we use the @Lazy annotation as well, then the @Bean or @Component will not be initialized until referenced by another bean (or explicitly retrieved from the enclosing BeanFactory). This is known as “lazy” initialization. Note that the default value of the @Lazy annotation is “true”, so we can omit it.
In our case, we will use the @Lazy annotation in our custom filter, in conjunction with the @Autowired setter method for the AuthenticationManager:
If you just make the above change, you will see that our application starts and runs OK.
In our case, the @Lazy annotation says to the Spring: “OK, we are inside a component, so this component should be initialized. But hold on, for a while, until the instantiation of the AuthenticationManager bean (defined in the configuration class), and after it has been instantiated, then you can fully instantiate this component (the custom filter). Then, when the configuration class requires the custom filter, the custom filter should have been instantiated, and thus pass it into it”.
As we’ve said, @Components by default are eagerly initialized by Spring, and this also means that all its dependencies are initialized as well, with one exception: the beans required in @Lazy annotated injection points (e.g.: those that annotated via @autowired). What actually happens, is the Spring creates a lazy-resolution proxy for all affected dependencies in the injection points. This delays the fully instantiation of the component until the first time is used elsewhere in our application. Then, the bean(s) required in injection point(s) inside the component should have been instantiated, a fact that causes the full instantiation of the component, which in its turn can be injected where it is needed.
Note that any autowiring in the Spring framework will happen after the dependency bean (annotated via @Autowired) has been constructed. So, if we want an AuthenticationManager bean to be autowired in the custom filter setter’s method, the AuthenticationManager bean should have been created earlier. The AuthenticationManager bean is defined in the configuration class. So, we have to wait for it. This is actually what @Lazy annotation does here.
This is due to the loading order of beans into the Spring context. @Compnent annotated class-beans tend to be loaded before the @Configuration classes. So, the order seems to be: the Components, then the Beans in Configuration classes, and finally the configuration classes themselves.
Solution 2 – @Autowired in a “config” method
When it comes to injection, the best approach is to use constructor injection for a class parameter. However, here we don’t want to do so, mainly because this is a configuration class and generally, I avoid using constructor injection in configuration classes.
The next best approach for injection is to inject (autowire) a parameter in a setter or a “config” method. Note that our configuration class is not a POJO-like class with setter methods, but we can also use any other method in our class. Such methods become “configuration” or “config” methods and they can be either public or private.
Generally, a “config” method annotated with @Autowired is called after field injection is done, and the autowired method parameters are injected upon the method call (when it is needed).
Here we are going to annotate via @Autowired the filterChain1() (SecurityFilterChain) method (which is also @Bean annotated), since this is the only method that needs the custom filter, in the configuration class. So, we can entirely remove the customFilter() filter method, and change the filterChain1() method, accordingly. Of course, we have to remove the @Lazy annotation from the setter method in the custom filter, as well.
So, the final versions of both of our classes are:
You can also find here the final repo.
One can think of other solution approaches, such as using a @PostConstruct annotated method or implementing in a class both: the ApplicationContextAware and InitializingBean interfaces, but in my opinion, they cannot be fitted well in our case. Apart from that the latter is a bit “heavier”/more complex implementation, they both can rather be used in cases where 2 classes are really mutual-dependent one to each other.
So, that’s it.
I hope you enjoyed this post.
Keep coding and stay tuned!