After an upgrade of one of our app in Spring Boot v2.7.6, I have an issue about a circular reference.
I have an abstract class like this:
public abstract class AbstractTransactionalService<Request, Response, Exception> {
#Autowired
private ApplicationContext applicationContext;
private AbstractTransactionalService<Request, Response, Exception> me;
#SuppressWarnings("unchecked")
#PostConstruct
public void init() {
me = applicationContext.getBean(this.getClass());
}
public Response performService(final Request request, final Class<Exception> exceptionClass)
throws Exception {
try {
final Response response = this.me.perform(request);
return response;
} catch (final Exception e) {
...
}
}
public abstract Response perform(Request request) throws Exception;
}
A service 2 extends AbstractTransactionalService and implements the perform() method. This service 2 is used in an other service 1 (injected with #Autowired and a call to performService() method is done).
I have a circular reference issue with the service that calls the service 2 extending the abstract class at server startup. When the service 1 does #Autowired for the service 2 extending the abstract class, the service 2 extending the abstract class is in creation. It seems that when the call to ApplicationContext.getBean() is done in the abstract class, it causes the circular reference error because he current bean is in creation.
I do not know how to solve it. Do you have an idea please?
I faced a similar issue and fixed it as follows. Created ServiceManager as a bean, autowired all the services involved in cycle(s) within it. And then retrieved the services via getters from the serviceManager. The serviceManager itself is to be retrieved via #Autowire where it is needed.
Related
It is a class which instance is connected to the external service and it is listening constantly of it.
#Component
public class Service extends PollingBot {
#Value("${token}")
private String token;
#Override
public void onUpdateReceived(Update update) {
if (update.hasMessage()) {
}
}
public void sendMessageToUser(String message) {
try {
execute(sendMessage);
} catch (ApiException e) {
}
}
}
You could see that there is a method called sendMessageToUser which send message. It could not be static because execute method not allow static context. This method could not be separeted to other class. /
So, I have to call this method from other class. However I don't want to create additional instance of Service class otherwise I have two instances which are listen for updates, but I want it is sole class instance doing so.
I have tried to run a Application Context and run method from it, but it was not worked.
So, my question is very simple. How could I run this class non-static(!) method from other class?
By default all spring managed beans are singleton. You need to use #Autowired to inject the bean into other and then you can call the methods of that bean.
#Autowired
private Service service;
public void sendMessage(String message){
service.sendMessageToUser(message);
}
You can use #Autowired annotation to call a method of a bean class(component) in Spring. Also, as mentioned by default beans are singleton in spring so you don't need to worry about creating a single instance explicitly every time.
Try to use the below code in the calling class:
#Autowired
private Service service;
public void sendText() {
service.sendMessage(message);
}
I am trying to create CustomWebServiceMessageReceiverHandlerAdapter which extends org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.
WebServiceMessageReceiverHandlerAdapter extends abstract WebServiceMessageReceiverObjectSupportwhich implements InitializingBean.
I have a problem, because I don’t understand why I have to call
afterPropertiesSet() in custom handler. I get an error without calling this method: “factory message is required”. But, this method is calling in abstract class, so my custom handler should run afterPropertiesSet() from abstract class. If you know the solution, let me know. Thanks a lot.
edit: This is my CustomWebServiceMessageReceiverHandlerAdapter :
public class CustomWebServiceMessageReceiverHandlerAdapter extends WebServiceMessageReceiverHandlerAdapter {
#Override
protected void handleInvalidXmlException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler,
InvalidXmlException ex) throws Exception {
//code
}
#Override
public void afterPropertiesSet() {
}
}
WebServiceMessageReceiverHandlerAdapter and WebServiceMessageReceiverObjectSupport are from Spring Framework
public class WebServiceMessageReceiverHandlerAdapter extends WebServiceMessageReceiverObjectSupport{}
There is no afterPropertiesSet()
public abstract class WebServiceMessageReceiverObjectSupport implements InitializingBean {
private WebServiceMessageFactory messageFactory;
/** Returns the {#code WebServiceMessageFactory}. */
public WebServiceMessageFactory getMessageFactory() {
return messageFactory;
}
/** Sets the {#code WebServiceMessageFactory}. */
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
this.messageFactory = messageFactory;
}
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(messageFactory, "messageFactory is required");
}
And now, when I am removing afterPropertiesSet() from my custom handler an exception is thrown. In my opinion, I don't understand something about life cycle of bean.
I'm unsure about your specific case. In general if a bean implements InitializingBean and thus the afterPropertiesSet this method is called after instantiation of the bean instance and after Spring injected all #Autowired properties/values.
In your specific case you need to ensure that messageFactory property of your (via inheritance) class is set. Typically this is done by Spring, if you provide a suitable setter for autowiring:
#Autowired
#Override
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
super.setMessageFactory(messageFactory);
}
If you overrride afterPropertiesSet without calling super.afterPropertiesSet() creation of the bean will work as the assertion of the super implementation is skipped. But you will likely encounter problems further down the line as the messageFactory property is not properly initialized.
I have created a custom Flink RichSinkFunction and attempted to autowire a JpaRepository within this custom class but I am constantly getting a NullPointerException.
If I autowire it in the constructor, I can see that the JpaRepo has been found - but when the invoke method is called, I receive a NullPointerException.
public interface MessageRepo extends JpaRepository<Message, Long> {
}
#Component
public class MessageSink extends RichSinkFunction<Message> {
private final transient MessageRepo messageRepo; //if i don't make this transient, i get the error message "The implementation of the RichSinkFunction is not serializable"
#Autowired
public MessageSink(MessageRepo messageRepo){
this.messageRepo = messageRepo;
messageRepo.save(new Message()); //no issues when i do this
}
#Override
public void invoke(Message message, Context context) {
// the message is not null
messageRepo.save(message); // NPE
}
Has anyone experienced this issue before? It looks like the MessageSink invoke method is being called in a separate thread which is why the messageRepo is always null?
Other parts of my code is able to use the MessageRepo apart from when I have my own custom sink.
I think the issue here is that flink needs to serialize the custom sink function before it distribute to its workers.
By marking the MessageRepo transit, meaning the field will be null when the worker node deserlize this function. Normally, you would initialise the transit dependency in the open function, which will be called after the object is deserialised.
I am not clearly sure about the reason, but I think spring boot gives priority to your service classes when it comes to injecting beans. I have faced a similar issue when I was trying to write a listener for my Entity class. This is how I solved it.
Create a component class which implements ApplicationContextAware interface and override setApplicationContext method. Have a static method in your class named getBean which will autowire on your first request. Sample code ---
#Component
public class SpringBeansUtil implements ApplicationContextAware {
private static ApplicationContext context;
#SuppressWarnings("static-access")
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
And then just get bean in your code ------->>
ClassName referenceName = (ClassName)SpringBeansUtil.getBean(ClassName.class);
I need to create a new EmployeeInfoCache instance (not a singleton) from info in the HttpServletRequest that is used to get info from an external app. I then want to give this object as a dependency to non-web-layer objects (where it will be set for all #Autowired references). EmployeeInfoCache itself has no web-layer dependencies (e.g. HttpServletRequest).
Can this be done? I thought about writing a spring interceptor which does the following but I don't know what to do to put an object in the spring context such that it will be used to resolve all #Autowired dependencies.
e.g.
public class MyInterceptor extends HandlerInterceptorAdapter
{
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception
{
- use info from HttpServletRequest to make calls to external app
- create EmployeeInfoCache object w/ this info
- add EmployeeInfoCache to spring application context where it will be used for resolution of #Autowired
}
}
And the remaining code:
// Assume don't have 'Component' or a similar annotation?
public class EmployeeInfoCache
{
...
}
// REST controller that calls the business logic method
#Controller
MyController
{
#Autowired
private MyBusinessObjectInterface myBusinessObject;
#RequestMapping(...)
public #ResponseBody MyResult myMethod(#RequestBody MyObject myObject, HttpServletRequest request, HttpServletResponse response)
{
myBusinessObject.doIt();
}
}
// Non-web-layer code that uses EmployeeInfoCache
#Service(...)
MyBusinessObject implements MyBusinessObjectInterface
{
// I want the EmployeeInfoCache instance created in MyInterceptor to be autowired here
#Autowired
private EmployeeInfoCache employeeInfoCache;
#Override
public void doIt()
{
employeeInfoCache.getName();
}
}
It sounds like you want to use a factory pattern. Have a Spring bean which is the factory method that returns the Cache.
http://kh-yiu.blogspot.in/2013/04/spring-implementing-factory-pattern.html
Let's assume I have this code:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService aService;
#RequestMapping("/doStuff")
public void doStuff(#RequestParam("type") String type) {
aService.doStuff();
}
}
In my application I need to call a specific service depending on the specified type. All services implements the same interface. If I understand correctly SomeService cannot be an interface. I could use a service factory and instantiate the service depending on the type every time a new request is done, but this doesn't look very efficient.
Alternatively I could use a different controller for each different type of service (and encode the type in the REST URI), but this would imply a lot of code duplication since all the services basically implements the same interface.
My question is, assuming the called service depends on the passed parameter, what is the best pattern to adopt for this scenario?
Similar to RC.'s answer, instead of using a Map and adding the values by you, just let the Spring BeanFactory handle this for you:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private BeanFactory beanFactory;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
SomeService aService = (SomeService)beanFactory.getBean(type);
aService.doStuff();
}
}
You could use a map here, something along this:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private SomeService someService;
#Autowired
private SomeOtherService someOtherService;
// ...
private final Map<String, ServiceCommonInterface> serviceMap = new HashMap<>();
#PostConstruct
private void postConstruct() {
serviceMap.put(typeForSomeService, someService);
serviceMap.put(typeForSomeOtherService, someOtherService);
}
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is correct (an enum might be handy here)
serviceMap.get(type).doStuff();
}
}
Or better, as stated in comments you can leverage qualifiers:
#Controller
#RequestMapping("/something")
public class SomeController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping("/doStuff")
public void login(#RequestParam("type") String type) {
// TODO: ensure type is a correct bean name
applicationContext.getBean(type, ServiceCommonInterface.class).doStuff();
}
}
Depending on the number of types you wish to support there are two options I see.
1) Autowire in a factory as you mentioned and lazily create each service as needed. If the services are stateless you could keep a reference to the object after created so would only need to create once per type.
2) Autowire in a Spring Map with the key being your types and the value being the correct service to use. Then when your receive the type, can retrieve the correct service impl for your map.
For example for map: http://www.mkyong.com/spring/spring-collections-list-set-map-and-properties-example/ or see How to inject a Map<String, List> in java springs?
Both of these require you to create an interface for your service which is something you said is possible.