Как определить, какая подсистема установлена? [Дубликат]

Поле, аннотированное @Autowired, является null, потому что Spring не знает о копии MileageFeeCalculator, которую вы создали с помощью new, и не знал, чтобы ее автоустанавливать.

Контейнер Spring Inversion of Control (IoC) имеет три основных логических компонента: реестр (называемый ApplicationContext) компонентов (beans), доступных для использования приложением, система настройки, которая вводит объектов в них путем сопоставления зависимостей с компонентами в контексте и решателя зависимостей, которые могут смотреть на конфигурацию множества различных компонентов и определять, как создавать и настраивать их в необходимом порядке.

Контейнер IoC не является волшебным, и он не может знать о Java-объектах, если вы как-то не сообщаете об этом. Когда вы вызываете new, JVM создает экземпляр нового объекта и передает его прямо вам - он никогда не проходит процесс настройки. Есть три способа настроить ваши компоненты.

Я опубликовал весь этот код, используя Spring Boot для запуска, в проекте GitHub ; вы можете посмотреть полный рабочий проект для каждого подхода, чтобы увидеть все, что вам нужно, чтобы заставить его работать. Тег с параметром NullPointerException: nonworking

Ввод ваших bean-компонентов

Наиболее предпочтительным вариантом является позволить Spring autowire все ваши компоненты; это требует наименьшего количества кода и является наиболее удобным для обслуживания. Чтобы сделать работу по автоустановке, как вы хотели, также автоустанавливайте MileageFeeCalculator следующим образом:

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

Если вам нужно создать новый экземпляр объекта службы для разных запросов, вы все равно можете использовать используя области весеннего компонента .

Тег, который работает путем ввода объекта службы @MileageFeeCalculator: working-inject-bean

Использовать @Configurable

Если вам действительно нужны объекты, созданные с new, которые будут автообновлены, вы можете использовать аннотацию Spring @Configurable вместе с AspectJ компиляцией во время компиляции для ввода ваших объектов , Этот подход вставляет код в конструктор вашего объекта, который предупреждает Spring о том, что он создается, так что Spring может настроить новый экземпляр. Это требует некоторой конфигурации в вашей сборке (например, компиляции с ajc) и включения обработчиков конфигурации среды Spring (@EnableSpringConfigured с синтаксисом JavaConfig). Этот подход используется системой активных записей Roo, чтобы позволить экземплярам new ваших объектов получать необходимую информацию о сохранении.

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}

Тег, который работает с помощью @Configurable на объекте службы: working-configurable

Ручной поиск: не рекомендуется

Этот подход подходит только для взаимодействия с устаревшим кодом в особых ситуациях. Почти всегда предпочтительнее создавать одноэлементный класс адаптеров, который Spring может использовать для autowire, и устаревший код может вызывать, но можно напрямую спросить контекст приложения Spring для bean-компонента.

Для этого вам нужно класс, к которому Spring может ссылаться на объект ApplicationContext:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

Затем ваш устаревший код может вызывать getContext() и извлекать необходимые ему компоненты:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
        return calc.mileageCharge(miles);
    }
}

Тег, который работает путем ручного поиска объекта службы в контексте Spring: working-manual-lookup

13
задан ragnar 29 January 2011 в 21:18
поделиться

3 ответа

Если вы пытаетесь упростить задачу пользователям вашей библиотеки (или что-то еще), вы можете просто сгенерировать как WinMain, так и main из вашего макроса. По умолчанию компоновщик устанавливает консольные приложения для запуска в main, а приложения win32 - с WinMain. Другая «основная» функция будет проигнорирована.

(Предположительно, остальная часть кода не использует ни один из аргументов основной функции (argc, argv, hInstance и т. Д.), , если это необходимо для работы с ними.)

Можно использовать определение _CONSOLE, но оно не появляется автоматически; вам нужно добавить его вручную в свойства проекта. С другой стороны, выбор символа запуска является автоматическим. Таким образом, просто предоставление обеих функций и возможность выбора компоновщика могут сделать жизнь проще, потому что разработчику проекта не нужно ничего устанавливать и действительно может переключиться с Windows на консольное приложение (возможно, даже на конфигурацию), не делая этого что-нибудь.

4
ответ дан user 20 August 2018 в 19:48
поделиться

_CONSOLE должен сделать трюк для вас. Также вы можете выбрать подсистему, используя #pragma comment( linker, "/subsystem:windows" ) или #pragma comment( linker, "/subsystem:console" ), если вы действительно хотите пройти этот маршрут.

11
ответ дан Eugen Constantin Dinca 20 August 2018 в 19:48
поделиться
  • 1
    Это, безусловно, лучший ответ, так как он напрямую отвечает на исходный вопрос о том, как вручную указывать систему, или позволяя компоновщику определить ее (или изменить настройки проекта). – leeor_net 7 February 2011 в 04:20
  • 2
    Как / где определяется _CONSOLE? – jww 2 October 2016 в 05:01

Это не так, как это работает. Вам нужно написать совершенно другой код в консольном приложении и в родном приложении Windows. В консольном приложении вы используете printf или cout для создания вывода, не так много, если оно используется для мыши. Для родного приложения Windows требуется цикл сообщений и создание окна с процедурой окна, которая обнаруживает сообщение WM_PAINT для обновления окна. Etcetera.

Но вы можете написать код, который делает оба. Просто напишите как функцию main (), так и функцию WinMain (), CRT автоматически вызовет правильный.

3
ответ дан Hans Passant 20 August 2018 в 19:48
поделиться
  • 1
    +1: Я пишу обе функции. – Puppy 29 January 2011 в 22:06
  • 2
    Хотя сделанные вами заявления верны, они не рассказывают всю историю. Можно написать приложение, которое работает с или без подсистемы консоли через несколько небольших твиков. Обычно это будет приложение без окон (или оно может просто вызвать MessageBox) и не иметь нити пользовательского интерфейса. Стандартные трубки доступны и для не консольных приложений, хотя, конечно, их вывод не будет отображаться, если не будет перенаправлен. – Tergiver 29 January 2011 в 22:08
  • 3
    В самом деле. Все мои приложения - консольные приложения в сборке отладки, и это в основном 6 строк дополнительного кода: основная функция, которая выполняет return WinMain(0,0,0,0), все внутри #ifdef _CONSOLE. Вы даже не нуждаетесь в #ifdef. – user 29 January 2011 в 22:54
Другие вопросы по тегам:

Похожие вопросы: