简体   繁体   中英

JpaRepository not autowiring in custom RichSinkFunction

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 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 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM