Использование репозиториев Spring в статических методах

Я определил 2 класса.

AndroidPush.java

public class AndroidPush {

    private static String SERVER_KEY = "XXXXX";
    private static String DEVICE_TOKEN = "XXXXX";
    public static void main(String[] args) throws Exception {
        String title = args[0];
        String message = args[1];
        sendPushNotification(title, message);
    }
    private static void sendPushNotification(String title, String message) throws Exception {
        String pushMessage = "{\"data\":{\"title\":\"" +
                title +
                "\",\"message\":\"" +
                message +
                "\"},\"to\":\"" +
                DEVICE_TOKEN +
                "\"}";
        URL url = new URL("https://fcm.googleapis.com/fcm/send");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("Authorization", "key = " + SERVER_KEY);
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        OutputStream outputStream = conn.getOutputStream();
        outputStream.write(pushMessage.getBytes());
    }
}

И

NotificationProcessing.java

public class NotificationProcessing {

    private static NotificationRepo notificationRepo;

    @Autowired
    public NotificationProcessing(NotificationRepo notificationRepo) {
        NotificationProcessing.notificationRepo = notificationRepo;
    }

    public static void addNotification(Offer offer) throws Exception {
        Notification notification = new Notification();
        notification.setId(null);
        notification.setMessage("There is new offer: " + offer.getTitle());
        notification.setLink("/offers/" + offer.getId());
        notificationRepo.save(notification);

        String[] arguments = new String[] {"New Offer", notification.getMessage()};
        AndroidPush.main(arguments);
    }
}

Я вызываю свой репозиторий внутри статического метода, например Франсиско Спит, ответившего на этот вопрос @Autowired и статический метод

Но затем, если я попытаюсь вызвать свой метод и сохранить уведомление, я получаю эту ошибку:

java.lang.NullPointerException: null

в этой строке: notificationRepo.save(notification);

Я полагаю, это связано с тем, что я использую репозиторий внутри статического метода, но если я удалю статику отовсюду и попытаюсь получить доступ к методу addNotification (), появится еще одна ошибка:

non-static method cannot be referenced from a static context

Я вызываю этот метод addNotification () внутри своего RestController

@RequestMapping(method = RequestMethod.POST)
public Offer newOffer (@RequestBody Offer offer) {
    NotificationProcessing.addCampaignNotification(offer);
    return repo.save(offer);
}

Итак, каково решение использования репозитория внутри статического метода?

Почему вы хотите использовать addNotification как статический метод?

aBnormaLz 21.12.2018 15:59

честно говоря, я не хочу использовать этот метод как статический, но если я удалю статический, появится вторая ОШИБКА: «на нестатический метод нельзя ссылаться из статического контекста», и я вообще не могу запустить приложение. Поэтому, если есть какое-либо предложение избежать этой ошибки, когда я не использую статику, и объяснение, почему это происходит, было бы полезно

Ante Ereš 21.12.2018 16:04
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
6 263
3

Ответы 3

Конструктор вызывается, когда вы создаете экземпляр своего объекта, поэтому нелогично помечать конструктор с помощью @Autowired и использовать внедренные экземпляры из статического контекста. Как я вижу, NotificationProcessing не помечен как @Component, поэтому я не уверен, что он вообще обрабатывается контейнером.

Я бы рекомендовал вам удалить модификаторы static из notificationRepo и addNotification(), пометив класс как @Component и вызвать addNotification() из внедренного экземпляра NotificationProcessing.

Указанный вопрос касается того, как ссылаться на поле экземпляра, введенное Spring из статического метода. Поскольку модификаторы static не имеют доступа к полям экземпляра, это может иметь смысл. Но это не стандарт, это обходной путь для устаревшего кода или библиотек, когда кажется сложным или невозможным сделать статический метод методом экземпляра.

I suppose this is because using repository inside of static ethod, but if I remove static from everywhere and try to access addNotification() method there is another error:

non-static method cannot be referenced from a static context

Вы ошиблись. Чтобы использовать зависимости bean-компонентов, вам необходимо внедрить их там, где они вам нужны, в других bean-компонентах. Вы никогда не будете определять методы с модификатором static в компоненте и вызывать его из другого компонента, добавляя префикс класса. Бобы - это экземпляры. Они не относятся к самому классу.

Кроме того, если notificationRepo.save(notification); запускает исключение NullPointerException, это означает одно: ваш класс не является bean-пружиной, потому что здесь контекст Spring не будет успешно загружен, если зависимость notificationRepo не может быть разрешена:

@Autowired
public NotificationProcessing(NotificationRepo notificationRepo) {
    NotificationProcessing.notificationRepo = notificationRepo;
}

Короче говоря, аннотируйте свой класс, чтобы он стал Spring Bean, и удалите все эти статические модификаторы:

@Component
public class NotificationProcessing {
    ...
}

И введите это в контроллер:

private NotificationProcessing notificationProcessing;

public MyController(NotificationProcessing notificationProcessing){
  this.notificationProcessing = notificationProcessing;
}

@RequestMapping(method = RequestMethod.POST)
public Offer newOffer (@RequestBody Offer offer) {
    notificationProcessing.addCampaignNotification(offer);
    return repo.save(offer);
}

Я думаю, вам следует изменить NotificationProcessing.addCampaignNotification(offer); на notificationProcessing.addCampaignNotification(offer); и вставить notificationProcessing в свой контроллер, добавив следующий конструктор:

@Autowired
public YourController(NotificationProcessing notificationProcessing) {
    this.notificationProcessing= notificationProcessing;
}

Другие вопросы по теме