SpringBoot: #Validated and #PreDestroy Error creating bean with name 'defaultValidator' - java

I have a Spring service with #PreDestroy method which calls another service
#Service
public class DestroyMe {
public final ValidService service;
private SomeDto dto;
#PreDestroy
public void destroy() {
service.stop(dto);
}
}
The ValidService its an interface with #Validated class level annotation
#Validated
public interface ValidService {
public void stop(#Valid SomeDto dto);
}
Also there's implementation class of this interface (with #Service annotation).
Validation works correctly in runtime, but when SprinBoot application terminates, it calls the destroy method which calls the service.stop(dto) and I get this error:
Error creating bean with name 'defaultValidator': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!).
Clicking on defaultValidator in IDE brings me into public static LocalValidatorFactoryBean defaultValidator() of ValidationAutoConfiguration class.
If I remove the #Validated annotation from the ValidatedService all works correctly but there's no service's input validation.
Looks like Spring is trying to create the validator bean ad-hoc to validate the input to stop method but it's not possible to do this in destroy phase.
How to solve this problem?
EDIT 1
Here is the code to reproduce this behavior: https://github.com/smacz/predestroy

A fix would be to replace the #PreDestroy annotation with #EventListener(ContextClosedEvent.class), if this makes sense in the context of your application.
Background
Beans are destroyed one by one. So when your Bean DestroyMe is being destroyed, it might happen, that the Validator-bean has already been destroyed. But a Validator bean is required, as the ValidService is annotated with #Validated. So Spring tries to load that bean from the application context. As the bean is not there, it tries to create a new instance for that bean, but this is not allowed while the application context is being shut down, as the exception states.
By switching from a pre-destroy method to an event listener which listens for the context closed event, one can run code, before any beans are destroyed.

Related

How does spring create proxy for a final class?

Maybe I have some outdated knowledge but it is the same as described here
https://stackoverflow.com/a/2657465/2674303
But now I noticed that this example works without any exceptions:
#Service
#EnableScheduling
public final class MyService {
#PostConstruct
public void init(){
System.out.println("MyService started");
}
#Scheduled(fixedDelay= 1000)
public void scheduleCall() {
System.out.println("scheduleCall");
}
}
Could you pease provide how does it work ?
#Scheduled annotation does not require proxy creation. The mechanism is different. After bean initialization Spring called post-processor ScheduledAnnotationBeanPostProcessor. Post processor searches for all methods annotated with #Scheduled and registers them to TaskScheduller for execution. Method execution will be performed via reflection.
See ScheduledAnnotationBeanPostProcessor source code.
#Scheduled
Processing of #Scheduled annotations is performed by registering a
ScheduledAnnotationBeanPostProcessor. This can be done manually or,
more conveniently, through the task:annotation-driven/ XML element
or #EnableScheduling annotation.
ScheduledAnnotationBeanPostProcessor
Bean post-processor that registers methods annotated with #Scheduled
to be invoked by a TaskScheduler according to the "fixedRate",
"fixedDelay", or "cron" expression provided via the annotation. This
post-processor is automatically registered by Spring's
task:annotation-driven XML element, and also by the
#EnableScheduling annotation.
Autodetects any SchedulingConfigurer instances in the container,
allowing for customization of the scheduler to be used or for
fine-grained control over task registration (e.g. registration of
Trigger tasks). See the #EnableScheduling javadocs for complete usage
details.
#PostConstruct also implemented via post-processor InitDestroyAnnotationBeanPostProcessor when dependency injection performed for bean, method which marked #PostConstruct will be executed thru reflection without proxy.
See InitDestroyAnnotationBeanPostProcessor source code
Summary:
In your example, Spring will create bean without proxy.
In case you will add a proxy-specific annotation, for example, #Transactional you will get an exception that proxy can not be created due to final class java.lang.IllegalArgumentException: Cannot subclass final class com.test.services.MyService
#Service
#EnableScheduling
public final class MyService {
#PostConstruct
public void init(){
System.out.println("MyService started");
}
#Scheduled(fixedDelay= 1000)
#Transactional
public void scheduleCall() {
System.out.println("scheduleCall");
}
}
But the current problem you also can solve to force use JDK dynamic proxy. We need to create an interface for class and set property spring.aop.proxy-target-class = false according to Proxying mechanisms

Context not active exception while injecting request scope bean in application scope class with Postconstruct method

when I tried to inject request scoped bean in application scope bean I got the following error.
Method threw 'org.jboss.weld.contexts.ContextNotActiveException' exception. Cannot evaluate com.example.flow.txn.TxnMessageProcessor$Proxy$_$$_WeldClientProxy.toString()
Code Reference:
#ApplicationScoped
public class TxnMessageObserver {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageObserver.class);
#Inject
private TxnMessageProcessor processor;
//message is observed here
public void postConstruct(#Observes #Initialized(ApplicationScoped.class) Object o) {
logger.info("Subscribing to queue [{}] for msg.", queue);
consumer.subscribe(queue);
}
}
#RequestScoped
public class TxnMessageProcessor {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageProcessor.class);
//all processing happens here
}
I need to process every message in request scope.
If the applicationscoped bean is constructed eagerly when the servlet context is initialized (like is the case here), there is no request context and hence no requestscoped bean.
Since it is completely unclear what you try to achieve (your code is not a minimal reproducible example, let me point you to
JEE6 #ApplicationScoped bean and concurrency
Why #Singleton over #ApplicationScoped in Producers?
(All found via this search)
Injecting a requestscoped bean is therefor dangerous and I strongly suggest to retrieve the required requestscoped bean in the specific methods or do it the other way around, inject the applicationscoped bean in the requestscoped one and call a method on it, passing in itself.
I do not know what exactly the problem cause is. But I can confirm that you can inject #ReqeustScoped beant into #ApplicationScoped. I do that in many applications with hundreds of classes and it worked out of the box.

How to specify a default bean for autowiring in Spring?

I am coding both a library and service consuming this library. I want to have a UsernameProvider service, which takes care of extracting the username of the logged in user. I consume the service in the library itself:
class AuditService {
#Autowired
UsernameProvider usernameProvider;
void logChange() {
String username = usernameProvider.getUsername();
...
}
}
I want to have a default implementation of the UsernameProvider interface that extracts the username from the subject claim of a JWT. However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername().
I naturally get an error when there are multiple autowire candidates of the same type (DefaultUsernameProvider in the library, and BasicAuthUsernameProvider in the service), so I'd have to mark the bean in the service as #Primary. But I don't want to have the library clients specify a primary bean, but instead mark a default.
Adding #Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work.
Adding #ConditionalOnMissingBean in a Configuration class in the library didn't work either.
EDIT: Turns out, adding #Component on the UsernameProvider implementation classes renders #ConditionalOnMissingBean useless, as Spring Boot tries to autowire every class annotated as a Component, therefore throwing the "Multiple beans of type found" exception.
You can annotate the method that instantiates your bean with #ConditionalOnMissingBean. This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean.
In the example below you must not annotate the class DefaultUserProvider as Component, Service or any other bean annotation.
#Configuration
public class UserConfiguration {
#Bean
#ConditionalOnMissingBean
public UserProvider provideUser() {
return new DefaultUserProvider();
}
}
You've not posted the code for DefaultUsernameProvider but I guess its annotated as a #Component so it is a candidate for auto wiring, and the same with the BasicAuthUsernameProvider. If you want to control which of these is used, rather than marking them both as components, add a #Configuration class, and create your UsernameProvider bean there:
#Configuration
public class ProviderConfig {
#Bean
public UsernameProvider() {
return new BasicAuthUsernameProvider();
}
}
This bean will then be auto wired wherever its needed

#PostConstruct annotation and spring lifecycle

I'm new to Spring, I would like to know:
I have a java class annotated with #Component (spring) and inside I have a method annotated with #PostConstruct. The class is then referenced by #Autowired annotated field in another class. Can I assume that the class is only injected after #PostConstruct is called?
#Component
class AuthenticationMetrics {
private static final MetricRegistry metrics = new MetricRegistry();
final Counter requestsTotal;
final Meter guestLogins;
final Meter kfUserLogins;
final Timer guestLoginResponseTime;
final Timer kfLoginResponseTime;
#PostConstruct
public void populateMetricsRegistry() {
metrics.counter("authentication.requests.totals");
}
}
If you are asking is injection of given class happening after #PostConstruct in that bean is called, then the answer is yes - #PostConstruct is executed before bean is considered as "injectable"
If you are asking if #PostConstruct on given bean is executed after all injections has been done (on the same bean) - then yes - #PostConstruct is executed after injections are commited to given bean. This is the reason it exists. Normally you could put #PostConstruct actions into the constructor. However, when new object is created (constructor is called) injections are not performed yet - so any initialization that depends on injected objects would fail due to NPE. That is why you need #PostConstruct
The handling of annotations such as #PostConstruct, #Resource, #PreDestroy is done via a BeanPostProcessor, in this case the CommonAnnotationBeanPostProcessor. You can see in the following diagram from Spring that these BPP's are handled after Dependency Injection but before Bean Ready For Use (Which means as much as injectable).
Yes. Bean creation workflow is:
constructior call
#Autowired fields
#Autowired setters
BeanPostProcessor's postProcessBeforeInitialization(), i.e. #PostConstruct called by CommonAnnotationBeanPostProcessor
InitializingBean.afterPropertiesSet()
BeanPostProcessor's postProcessAfterInitialization()
Bean is ready and can be injected to other bean

Autowire of prototype bean into prototype bean?

I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.

Categories

Resources