Определение «количество месяцев в разнице» подлежит многому толкованию. : -)
Вы можете получить год, месяц и день месяца из объекта даты JavaScript. В зависимости от того, какую информацию вы ищете, вы можете использовать их для определения количества месяцев между двумя моментами времени.
Например, вне манжеты, это выясняет, сколько полные месяцы лежат между двумя датами, не считая частичных месяцев (например, за исключением месяца, в котором находится каждая дата):
function monthDiff(d1, d2) {
var months;
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
months += d2.getMonth();
return months <= 0 ? 0 : months;
}
monthDiff(
new Date(2008, 10, 4), // November 4th, 2008
new Date(2010, 2, 12) // March 12th, 2010
);
// Result: 15: December 2008, all of 2009, and Jan & Feb 2010
monthDiff(
new Date(2010, 0, 1), // January 1st, 2010
new Date(2010, 2, 12) // March 12th, 2010
);
// Result: 1: February 2010 is the only full month between them
monthDiff(
new Date(2010, 1, 1), // February 1st, 2010
new Date(2010, 2, 12) // March 12th, 2010
);
// Result: 0: There are no *full* months between them
(обратите внимание, что значения месяца в JavaScript начинаются с 0 = Январь .)
Включение дробных месяцев в вышеизложенное намного сложнее, потому что три дня в типичном феврале составляют большую часть этого месяца (~ 10,714%), чем три дня в августе (~ 9,677%), и, конечно, даже февраль - это движущаяся цель в зависимости от того, является ли это високосным годом.
Есть также некоторые библиотеки даты и времени , доступные для JavaScript, которые, вероятно, делают это проще .
Поле, аннотированное @Autowired
, является null
, потому что Spring не знает о копии MileageFeeCalculator
, которую вы создали с помощью new
, и не знал, чтобы ее автоустанавливать.
Контейнер Spring Inversion of Control (IoC) имеет три основных логических компонента: реестр (называемый ApplicationContext
) компонентов (beans), доступных для использования приложением, система настройки, которая вводит объектов в них путем сопоставления зависимостей с компонентами в контексте и решателя зависимостей, которые могут смотреть на конфигурацию множества различных компонентов и определять, как создавать и настраивать их в необходимом порядке.
Контейнер IoC не является волшебным, и он не может знать о Java-объектах, если вы как-то не сообщаете об этом. Когда вы вызываете new
, JVM создает экземпляр нового объекта и передает его прямо вам - он никогда не проходит процесс настройки. Есть три способа, которыми вы можете настроить свои компоненты.
Я опубликовал весь этот код, используя Spring Boot для запуска, в проекте GitHub ; вы можете посмотреть полный рабочий проект для каждого подхода, чтобы увидеть все, что вам нужно, чтобы заставить его работать. Тег с параметром NullPointerException
: nonworking
Наиболее предпочтительным вариантом является позволить 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
Если вам действительно нужны объекты, созданные с 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
UPDATE: Действительно умные люди быстро указали на этот ответ , который объясняет странность, описанную ниже
ОРИГИНАЛЬНЫЙ ОТВЕТ:
я знаю, помогает ли это кому-либо, но я был застрял с той же проблемой, даже когда делал что-то вроде правды. В моем основном методе у меня есть такой код:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
и в файле token.xml
у меня была строка
<context:component-scan base-package="package.path"/>
Я заметил, что пакет .path больше не существует, поэтому я просто положил строку навсегда.
И после этого NPE начал заходить. В pep-config.xml
у меня было всего 2 боба:
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
и класс SomeAbac имеет свойство, объявленное как
@Autowired private Settings settings;
по неизвестной причине, настройки null в init (), когда элемент <context:component-scan/>
отсутствует вообще, но когда он присутствует и имеет некоторые bs в качестве basePackage, все работает Что ж. Теперь эта строка выглядит так:
<context:component-scan base-package="some.shit"/>
, и она работает. Может быть, кто-то может дать объяснение, но для меня это достаточно прямо сейчас)
<context:component-scan/>
неявно разрешает <context:annotation-config/>
, необходимый для работы @Autowired
.
– ForNeVeR
12 October 2017 в 04:55
Если вы не кодируете веб-приложение, убедитесь, что ваш класс, в котором выполняется @Autowiring, является весенним бобом. Как правило, весенний контейнер не будет знать о классе, который мы могли бы назвать весенним бобом. Мы должны рассказать весенний контейнер о наших весенних классах.
Этого можно достичь путем настройки в appln-contxt или лучший способ - аннотировать класс как @Component и, пожалуйста, не создавайте аннотированный класс, используя новый оператор. Убедитесь, что вы получили его из контекста Appln, как показано ниже.
@Component
public class MyDemo {
@Autowired
private MyService myService;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("test");
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
System.out.println("ctx>>"+ctx);
Customer c1=null;
MyDemo myDemo=ctx.getBean(MyDemo.class);
System.out.println(myDemo);
myDemo.callService(ctx);
}
public void callService(ApplicationContext ctx) {
// TODO Auto-generated method stub
System.out.println("---callService---");
System.out.println(myService);
myService.callMydao();
}
}
Вы также можете исправить эту проблему, используя аннотацию @Service в классе службы и передав требуемый bean classA в качестве параметра в другой конструктор класса bean bean и аннотировать конструктор класса B с @Autowired. Пример фрагмента здесь:
@Service
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void useClassAObjectHere(){
classA.callMethodOnObjectA();
}
}
Я новичок в Spring, но я обнаружил это рабочее решение. Скажите, пожалуйста, если это неприемлемо.
Я делаю Spring applicationContext
в этом компоненте:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils {
public static ApplicationContext ctx;
/**
* Make Spring inject the application context
* and save it on a static variable,
* so that it can be accessed from any point in the application.
*/
@Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
Вы можете поместить этот код в основную класс приложения, если вы хотите.
Другие классы могут использовать его следующим образом:
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
Таким образом, любой bean-компонент может быть получен любым объектом в приложении (также запутанным с new
) и статическим способом.
На самом деле, вы должны использовать управляемые объекты JVM или Spring-managed Object для вызова методов. из вашего вышеуказанного кода в классе контроллера вы создаете новый объект для вызова своего класса обслуживания, у которого есть объект с автоматической проводкой.
MileageFeeCalculator calc = new MileageFeeCalculator();
, поэтому он не будет работать таким образом.
Решение делает этот MileageFeeCalculator как объект с автоматической проводкой в самом контроллере.
Измените свой класс контроллера, как показано ниже.
@Controller
public class MileageFeeController {
@Autowired
MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
Я думаю, вы упустили, чтобы проинструктировать весну для сканирования классов с аннотацией.
Вы можете использовать @ComponentScan("packageToScan")
в классе конфигурации вашего весеннего приложения, чтобы проинструктировать весну для сканирования.
@Service, @Component
и т. д. аннотации добавляют мета-описание.
Spring только вводит экземпляры тех классов, которые либо создаются как bean-элементы, либо помечены аннотацией.
Классы, отмеченные аннотацией, должны быть идентифицированы весной перед инъекцией, @ComponentScan
указать весну найдите классы, отмеченные аннотацией. Когда Spring находит @Autowired
, он ищет связанный компонент и вставляет требуемый экземпляр.
Добавление только аннотации, не исправляет или облегчает инъекцию зависимостей, Spring должна знать, где искать.
Если это происходит в тестовом классе, убедитесь, что вы не забыли аннотировать класс.
Например, в Spring Boot:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
....
Другим решением было бы поставить вызов: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
в конструктор MileageFeeCalculator следующим образом:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- will be autowired when constructor is called
public MileageFeeCalculator() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Однажды я столкнулся с той же проблемой, когда я не совсем привык к the life in the IoC world
. Поле @Autowired
одного из моих bean-компонентов является нулевым во время выполнения.
Основная причина заключается в том, что вместо использования автоматически созданного компонента, поддерживаемого контейнером Spring IoC (чье поле @Autowired
равно indeed
] правильно введенный), я newing
мой собственный экземпляр этого типа бобов и его использование. Конечно, это поле @Autowired
равно нулю, потому что Spring не имеет возможности его ввести.
Кажется, что это редкий случай, но вот что со мной произошло:
Мы использовали @Inject
вместо @Autowired
, который является стандартом javaee, поддерживаемым Spring. В каждом месте он работал нормально, а бобы вводили правильно, а не в одно место. Инъекция компонента выглядит одинаково
@Inject
Calculator myCalculator
Наконец, мы обнаружили, что ошибка заключалась в том, что мы (фактически, функция автозавершения Eclipse) импортировали com.opensymphony.xwork2.Inject
вместо javax.inject.Inject
!
Итак, чтобы суммировать, убедитесь, что ваши аннотации (@Autowired
, @Inject
, @Service
, ...) имеют правильные пакеты!
Ваша проблема новая (создание объекта в стиле java)
MileageFeeCalculator calc = new MileageFeeCalculator();
С аннотацией @Service
, @Component
, @Configuration
beans создаются в контексте приложения Spring при запуске сервера , Но когда мы создаем объекты с использованием нового оператора, объект не регистрируется в контексте приложения, который уже создан. Для примера используется класс Employee.java.
Проверьте это:
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String name = "tenant";
System.out.println("Bean factory post processor is initialized");
beanFactory.registerScope("employee", new Employee());
Assert.state(beanFactory instanceof BeanDefinitionRegistry,
"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (name.equals(definition.getScope())) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
}
}
}
}
@Configuration
, где метод создания экземпляра конкретного класса bean аннотируется с помощью@Bean
. – Donal Fellows 11 November 2013 в 02:12@Bean
при использовании Spring Proxy AOP? – chrylis 11 November 2013 в 02:16@Autowired MileageFeeCalculator calc
. Есть предположения? – Theo 14 July 2014 в 23:00ApplicationContext
. Некоторые пользователи (для которых я закрыл как дубликаты) не понимают этого. – Sotirios Delimanolis 18 October 2014 в 02:39