Spring IoC, Пример учебника по Spring Bean

Добро пожаловать в учебник по примерам использования Spring IoC. Фреймворк Spring основан на принципе инверсии управления. Внедрение зависимостей – это техника реализации IoC в приложениях. Внедрение зависимостей – это техника реализации IoC в приложениях.

Spring IoC

Сегодня мы рассмотрим контейнер Spring IoC. Мы также изучим Spring Bean. Ниже приведена таблица содержания для быстрой навигации по разделам учебника Spring IoC.

  1. Spring IoC
  2. Spring Bean
  3. Области видимости Spring Bean
  4. Конфигурация Spring Bean
  5. Пример Spring IoC и Spring Bean
    1. Конфигурация Spring Bean на основе XML
    2. Конфигурация Spring Bean с использованием аннотаций
    3. Конфигурация Spring Bean на основе Java

Контейнер Spring IoC

Spring IoC – механизм достижения слабой связи между зависимостями объектов. Для достижения слабой связи и динамического связывания объектов во время выполнения зависимости объектов внедряются другими объектами-сборщиками. Контейнер Spring IoC – это программа, которая внедряет зависимости в объект и готовит его к использованию. Мы уже рассмотрели, как мы можем использовать Внедрение Зависимостей Spring для реализации IoC в наших приложениях. Классы контейнера Spring IoC являются частью пакетов `org.springframework.beans` и `org.springframework.context`. Контейнер Spring IoC предоставляет нам различные способы отделения зависимостей объектов. `BeanFactory` является корневым интерфейсом контейнера Spring IoC. `ApplicationContext` является дочерним интерфейсом интерфейса `BeanFactory`, который предоставляет функции Spring AOP, i18n и т. д. Некоторые полезные дочерние интерфейсы `ApplicationContext` – это `ConfigurableApplicationContext` и `WebApplicationContext`. Spring Framework предоставляет ряд полезных классов реализации ApplicationContext, которые мы можем использовать для получения контекста Spring, а затем Spring Bean. Некоторые из полезных реализаций ApplicationContext, которые мы используем, включают;

  • AnnotationConfigApplicationContext: Если мы используем Spring в автономных java-приложениях и используем аннотации для конфигурации, то мы можем использовать это для инициализации контейнера и получения объектов бина.
  • ClassPathXmlApplicationContext: Если у нас есть файл конфигурации spring bean в автономном приложении, тогда мы можем использовать этот класс для загрузки файла и получения объекта контейнера.
  • FileSystemXmlApplicationContext: Это аналогично ClassPathXmlApplicationContext, за исключением того, что файл конфигурации xml можно загрузить откуда угодно в файловой системе.
  • AnnotationConfigWebApplicationContext и XmlWebApplicationContext для веб-приложений.

Обычно, если вы работаете с приложением Spring MVC и ваше приложение настроено на использование Spring Framework, контейнер управления внедрением зависимостей (IoC) Spring инициализируется при запуске приложения, и когда требуется бин, зависимости внедряются автоматически. Однако для автономного приложения вам нужно инициализировать контейнер где-то в приложении, а затем использовать его для получения spring beans.

Spring Bean

Spring Bean – это ничего особенного, любой объект в Spring framework, который мы инициализируем через контейнер Spring, называется Spring Bean. Любой обычный класс Java POJO может быть Spring Bean, если он настроен на инициализацию через контейнер, предоставив метаданные конфигурации.

Spring Bean Scopes

Есть пять областей определения для бинов Spring.

  1. singleton – Для каждого контейнера будет создан только один экземпляр бина. Это область по умолчанию для бинов Spring. При использовании этой области убедитесь, что у бина нет общих переменных экземпляра, иначе это может привести к проблемам с несогласованностью данных.
  2. prototype – Новый экземпляр будет создан каждый раз, когда запрашивается бин.
  3. request – Это то же самое, что и область prototype, однако она предназначена для использования в веб-приложениях. Новый экземпляр бина будет создан для каждого HTTP-запроса.
  4. session – Для каждой HTTP-сессии контейнер будет создавать новый бин.
  5. global-session – Это используется для создания глобальных сессионных бинов для приложений портлетов.

Фреймворк Spring расширяем, и мы также можем создавать свои собственные области. Однако большую часть времени нам хватает областей, предоставляемых фреймворком.

Конфигурация бинов Spring

Фреймворк Spring предоставляет три способа настройки бинов для использования в приложении.

  1. Конфигурация на основе аннотаций – Путем использования аннотаций @Service или @Component. Подробности области действия могут быть предоставлены с помощью аннотации @Scope.
  2. Конфигурация на основе XML – Путем создания файла конфигурации Spring XML для настройки бинов. Если вы используете фреймворк Spring MVC, конфигурация на основе XML может быть загружена автоматически с помощью написания некоторого шаблонного кода в файле web.xml.
  3. Конфигурация на основе Java – Начиная с версии Spring 3.0, мы можем настраивать бины Spring с помощью программ на Java. Некоторые важные аннотации, используемые для конфигурации на Java, это @Configuration, @ComponentScan и @Bean.

Пример проекта Spring IoC и Spring Bean

Давайте рассмотрим различные аспекты контейнера Spring IoC и конфигурацию бинов Spring с помощью простого проекта Spring. В качестве примера я создаю проект Spring MVC в Spring Tool Suite. Если вы новичок в Spring Tool Suite и Spring MVC, пожалуйста, прочитайте Учебник по Spring MVC с Spring Tool Suite. Финальная структура проекта выглядит как на изображении ниже. Давайте рассмотрим различные компоненты проекта Spring IoC и Spring Bean по очереди.

Конфигурация Spring Bean на основе XML

MyBean – это простой класс Java POJO.

package com.journaldev.spring.beans;

public class MyBean {

	private String name;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

Файл конфигурации Spring XML

Код servlet-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="https://www.springframework.org/schema/beans"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.journaldev.spring" />
	
	<beans:bean name="myBean" class="com.journaldev.spring.beans.MyBean" scope="singleton" ></beans:bean>
	
</beans:beans>

Обратите внимание, что MyBean настроен с использованием элемента bean с областью действия singleton.

Конфигурация Spring Bean на основе аннотаций

package com.journaldev.spring.beans;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.context.WebApplicationContext;

@Service
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class MyAnnotatedBean {

	private int empId;

	public int getEmpId() {
		return empId;
	}

	public void setEmpId(int empId) {
		this.empId = empId;
	}
	
}

МойАннотированныйБин настроен с использованием @Service, а область установлена в значение Request.

Класс контроллера Spring IoC

Класс HomeController будет обрабатывать HTTP-запросы для домашней страницы приложения. Мы будем внедрять наши бобы Spring в этот класс контроллера через контейнер WebApplicationContext.

package com.journaldev.spring.controller;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.journaldev.spring.beans.MyAnnotatedBean;
import com.journaldev.spring.beans.MyBean;

@Controller
@Scope("request")
public class HomeController {
		
	private MyBean myBean;
	
	private MyAnnotatedBean myAnnotatedBean;

	@Autowired
	public void setMyBean(MyBean myBean) {
		this.myBean = myBean;
	}

	@Autowired
	public void setMyAnnotatedBean(MyAnnotatedBean obj) {
		this.myAnnotatedBean = obj;
	}
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		System.out.println("MyBean hashcode="+myBean.hashCode());
		System.out.println("MyAnnotatedBean hashcode="+myAnnotatedBean.hashCode());
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
}

Файл развертывания

Нам нужно настроить наше приложение для Spring Framework, чтобы метаданные конфигурации были загружены, и контекст был инициализирован.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

Почти весь вышеуказанный код является шаблонным кодом, созданным автоматически с помощью инструмента STS.

Запустите пример приложения бина Spring IoC

Теперь, когда вы запустите веб-приложение, домашняя страница будет загружена, и в консоли будут выведены следующие журналы при многократном обновлении страницы.

MyBean hashcode=118267258
MyAnnotatedBean hashcode=1703899856
MyBean hashcode=118267258
MyAnnotatedBean hashcode=1115599742
MyBean hashcode=118267258
MyAnnotatedBean hashcode=516457106

Обратите внимание, что MyBean настроен как синглтон, поэтому контейнер всегда возвращает один и тот же экземпляр, и хэш-код всегда одинаковый. Аналогично, для каждого запроса создается новый экземпляр MyAnnotatedBean с разным хэш-кодом.

Настройка Java-основанного Spring Bean

Для автономных приложений мы можем использовать как аннотационную, так и XML-основанную конфигурацию. Единственное требование – инициализировать контекст где-то в программе перед его использованием.

package com.journaldev.spring.main;

import java.util.Date;

public class MyService {

	public void log(String msg){
		System.out.println(new Date()+"::"+msg);
	}
}

MyService – это простой класс Java с некоторыми методами.

package com.journaldev.spring.main;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value="com.journaldev.spring.main")
public class MyConfiguration {

	@Bean
	public MyService getService(){
		return new MyService();
	}
}

Класс конфигурации на основе аннотаций, который будет использоваться для инициализации контейнера Spring.

package com.journaldev.spring.main;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyMainClass {

	public static void main(String[] args) {
		
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
				MyConfiguration.class);
		MyService service = ctx.getBean(MyService.class);
		
		service.log("Hi");
		
		MyService newService = ctx.getBean(MyService.class);
		System.out.println("service hashcode="+service.hashCode());
		System.out.println("newService hashcode="+newService.hashCode());
		ctx.close();
	}

}

A simple test program where we are initializing the AnnotationConfigApplicationContext context and then using getBean() method to get the instance of MyService. Notice that I am calling getBean method two times and printing the hashcode. Since there is no scope defined for MyService, it should be a singleton and hence hashcode should be the same for both the instances. When we run the above application, we get following console output confirming our understanding.

Sat Dec 28 22:49:18 PST 2013::Hi
service hashcode=678984726
newService hashcode=678984726

Если вы ищете XML-основанную конфигурацию, просто создайте файл конфигурации Spring XML, а затем инициализируйте контекст с помощью следующего фрагмента кода.

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        MyService app = context.getBean(MyService.class);

Это все для примера учебника Spring IoC, областей видимости бинов Spring и деталей конфигурации. Скачайте проект примера Spring IoC и Spring Bean по ссылке ниже и попробуйте поработать с ним, чтобы лучше понять.

Скачать проект Spring Beans

Ссылка: Страница Spring.IO для IOC

Source:
https://www.digitalocean.com/community/tutorials/spring-ioc-bean-example-tutorial