Application failed to start with #Async annotation - java

I am trying to run a function in background asynchronously. For this I am trying Spring's #Async annotation but my application is unable to start after putting this annotation on the function.
I tried
#EnableAsync(proxyTargetClass = true)
but still no luck.
Below is the message I am getting on application start.
APPLICATION FAILED TO START
Description:
The bean 'MyBatchSyncProcessor' could not be injected as a 'com.a.b.c.service.MyBatchSyncProcessor' because it is a JDK dynamic proxy that implements:
com.a.b.c.service.BaseSyncProcessor
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
Please help me out in getting this application up and running.

Don't inject your service implementation (MyBatchSyncProcessor) - inject its interface BaseSyncProcessor.

Although the first answer is correct, it doesn't really touches on why:
From https://www.fatalerrors.org/a/0dx20j8.html :
Async registers a Configuration configuration class with Spring using Spring's ImportSelector method, and injects a BeanPostProcessor, which calls the postProcessAfterInitialization method after the bean is instantiated to generate dynamic proxies for the object (if the target class implements an interface, the JDK proxy is used by default, otherwise CGLib is used)
When you combine this with :
(https://www.tutorialspoint.com/difference-between-jdk-dynamic-proxy-and-cglib-proxy-in-spring)
JDK dynamic proxy is available with the JDK. It can be only proxy by interface so target class needs to implement interface. In your is implementing one or more interface then spring will automatically use JDK dynamic proxies.
Now it becomes apparent that once you add the #EnableAsync aspect,
you need to inject the interface BaseSyncProcessor rather than its implementation MyBatchSyncProcessor, in beans that use the #Async annotation.

Related

Lazy load spring auto configuration

I have dependency in my spring boot project which fetches values of some properties using Spring's EnvironmentPostProcessor.
Now these properties are database credentials and not everyone has access to the credential since there is no dev environment for the db in question. I just want to change the configuration that the credentials don't get fetched on dev or local environment on application startup as that would result in a error and the application will fail to start.
Class A implements EnvironmentPostProcessor{}
I tried to use #Lazy annotation on the Class Annoteted with #ConfigurationProperties. I also tried using my own BeanFactoryPostProcessor (with #Order(HighestPrecedence) to programmatically set the A to lazy load, but it gets called before my BeanFactoryPostProcessor's postProcessBeanFactory method.
Is what I'm trying to achieve possible and am I going about it the wrong way?
#Lazy is only to be used with #Bean or #Component (Or any #Component-based annotations ex. #Service)
Take note: You can also add it to a #Configuration class, but that just means that all Beans in the class are annotated with #Lazy
#Lazy is a bit of a weird annotation in general; it should be seen as an IF possible then lazy load. If some other bean needs the lazy bean, the lazy bean will be initialized. (It's like the Pirate code, more of a guideline than an enforced rule)
Finally, marking #ConfigurationProperties with #Lazy seems a bit odd. As Spring will need these Configuration property "beans" to create the Spring Context.
However, the common use case for #Lazy is a failing database connection, preventing the application from starting. See the question if that is what you are running into.
Summary:
You can configure your repositories to be lazy-loaded with:
spring.data.jpa.repositories.bootstrap-mode=lazy
Last remark (Me just guessing)
If you wish to change properties once your application is already running, I would look at the following tutorial. It goes into manually reloading configuration and also #RefreshScope.
According to documentation EnvironmentPostProcessors must be registered via META-INF/spring.factories:
Allows for customization of the application's Environment prior to the
application context being refreshed. EnvironmentPostProcessor
implementations have to be registered in META-INF/spring.factories,
using the fully qualified name of this class as the key.
Implementations may implement the Ordered interface or use an #Order
annotation if they wish to be invoked in specific order.

Spring creating bean without proxy

In my some project I run into problem. Annotation #Transactional in some classes didn't work. After restarted module annotation is work. I open class in debug and saw that the CGLIB proxy is not used in the class, and used if I restart module without changes!
Eventually the problem was because project has custom library when in some class in #PostConstruct was registered beans duplicates of my beans with beanDefinitionRegistry.registerBeanDefinition() and after bean override in the part time class work without proxy. But I can't understand why? Why Spring create/ or replace/ or use bean without CGLIB proxy?
I was fixed that in my context, but I don't understand.

How to add a EJB Interceptor programmatically?

I'm trying to add a Interceptor in a EJB at runtime programmatically via CDI extensions.
This EJB exposes a Remote interface for remote calls. But I'm trying to add this Interceptor in the implementation class of this EJB adding the #Interceptors annontation like in this other SO question (CDI Extensions - Add Interceptors in ProcessAnnotatedType phase)
I think the CDI Extension only executes after the EJB are already registered because the Interceptor is never called.
But, for test purpose I have successfully register and execute an Interceptor programmatically in a simple CDI Bean.
The problem is when I'm try to register in a EJB.
Am I missing something?
Edit:
I'm using Wildfly 8
I think the key problem here is the difference between #Interceptors (EJB ones) and #Interceptor (CDI ones). CDI does not govern EJB container hence adding the EJB annotation (#Interceptors) in CDI extension won't necessarrily kick EJB logic into effect - EJB container might have started at that moment and it won't know of the annotation. Furthermore the CDI extension would add this annotation to the AnnotatedType which is a structure EJB probably won't make use of. On the other hand, all this really depends on the application server as it is responsible for CDI/EJB integration hence as a "bonus" the behavior might differ between AS.
CDI extension is something which allows you to hook into CDI bootstrap lifecycle, therefore you are able to use/enable/add CDI interceptors. I would try going that way instead. BTW even the SO question you referred to speaks of beans.xml/#Priority for enablement which means it uses CDI interceptors and not EJB ones.
Also, an EJB bean should automatically become CDI bean therefore you can attach CDI interceptor to it without changing the bean itself.

Where do those beans returned by Spring getBean method come from?

Could you please list all possible sources of getBean?
BTW, If I just write context.getBean(SomeInterface.class), can I get the implementation of the interface class?
They come from the Spring application context (which is what you are calling the getBean method on).
Spring has this concept of an application context, which is an object that contains things such as all the beans managed by Spring.
You put beans in the application context by configuring them in a Spring XML configuration file or by annotating classes with annotations such as #Component, #Service etc. and then letting Spring find them by scanning packages for those classes.
If you write context.getBean(SomeInterface.class) and there is a Spring bean that implements that interface, then that method call will return the bean that implements the interface.
These are basic concepts of the Spring framework. See chapter 5, The IoC Container in the Spring documentation for a detailed explanation of how it works.
If you go into the ApplicationContext class hierarchy, you will find that all spring Application Context file are child of org.springframework.core.io.DefaultResourceLoader class.
What DefaultResourceLoader does is it get the current thread context class loader(if none is provided). So we can understand that all application context file first load the classes defined. Application Context load all the beans defined in xml file, marked using #Bean annotation or other available spring annotations. Once the context scan through the annotation and/ or xml and load all the beans in the class loader. Context first create the dependencies and inject them in dependent.
To get context.getBean(SomeInterface.class), please refer below documentation.
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/context/support/AbstractApplicationContext.html#getBean(java.lang.Class)
As per my understanding of documentation, you shall get the bean if exact one implementation bean class is defined.

How to get a 'JBoss service' with CDI in JMX with AS6?

I'm currently migrating a JBoss service class from AS5.1 to AS6 (not going to AS7 for a variety of reasons).
For AS5.1, the service implements a {serviceName}MBean and has a jboss-service.xml with attribute values. It's packaged in a jboss-sar, which is packaged in an EAR to be deployed. When deployed, the service fields are populated with the values from jboss-service.xml, and the service is automatically registered into JMX.
I would like to achieve the same thing using AS6, but would like the service to support CDI - so I'd like its new #Inject injection points to be satisfied. I need these to be satisfied in the object registered with JMX, so that methods called via JMX can reference injected fields, but I'm struggling to achieve this.
I've had to package the service in a jar, instead of a jboss-sar, for classloader reasons, but let's say it's otherwise unchanged. When deployed to AS6, all works as before - service goes into JMX, values from XML propagate to the object. However, the instance created does not have its CDI injection points satisfied, and neither does the object registered in JMX.
If I annotate the service class with #Startup and #javax.ejb.Singleton, but keep its interface and the jboss-service.xml, the object registered into JMX still does not have its CDI injection points satisfied. However if I programmattically deregister that bean, and re-register the instance in a #PostConstruct method, then the bean in JMX DOES have its injection points satisfied. However that bean no longer has the values specified in the jboss-service.xml.
So how can I get the best of both worlds? CDI and the usual JBoss service behaviour? What is the correct way to implement a JBoss service with CDI? I've been unable to find documentation on this. Hope someone can help.
Thanks,
Ben
As a worst-case fallback, you should be able to use the CDI extension API to get your service to be injected. I don't think you would need to write a fully-fledged extension, but if you have an initialisation hook in the service object, you can do this (lifted with minor editing from the docs, not compiled or tested):
public static <T> void inject(T object) {
BeanManager beanManager = (BeanManager)new InitialContext().lookup("java:comp/BeanManager");
AnnotatedType<T> type = beanManager.createAnnotatedType(object.getClass());
InjectionTarget<T> it = beanManager.createInjectionTarget(type);
CreationalContext ctx = beanManager.createCreationalContext(null);
it.inject(object, ctx);
it.postConstruct(object);
}
Basically, any object to that method will get injected. All the usual CDI annotations should work. Hopefully.
As mentioned in the comments above, it seems Tom's right - there's no 'nice' way of created a CDIed, JMX bean in one go, you either have to put your JMX bean in CDI, as is suggested above, or put you CDIed bean into JMX. We tried the former, but it appears the BeanManager isn't bound to JNDI at the point the service starts up.
So instead we went with CDI bean -> JMX. We're creating the services as Singleton EJBs, so their injection points are satisfied, and they then get registered/unregistered to JMX in their PostConstruct/PreDestroy methods, using German Escobar's excellent CDI portable extension (germanescobar.net/2010/01/cdi-portable-extension-jmx.html, community.jboss.org/thread/148750 is also helpful).
May try to use ApplicationScoped beans and get them to start by observing a ContainerInitialized(?) event, however, as we don't need all the features of an EJB. Haven't tried that yet, mind...

Categories