Spring IoC, Exemplo de Tutorial Spring Bean

Bem-vindo ao Tutorial de Exemplo Spring IoC. O Spring Framework é construído no princípio da Inversão de Controle. Injeção de dependência é a técnica para implementar IoC em aplicações.

Spring IoC

Hoje vamos olhar para o Contêiner Spring IoC. Também passaremos pelo Spring Bean. Abaixo está a tabela de conteúdos para uma rápida navegação para diferentes seções do tutorial Spring IoC.

  1. Spring IoC
  2. Spring Bean
  3. Escopos de Spring Bean
  4. Configuração de Spring Bean
  5. Exemplo de Spring IoC e Spring Bean
    1. Configuração de Spring Bean Baseada em XML
    2. Configuração de Spring Bean Baseada em Anotação
    3. Configuração de Spring Bean Baseada em Java

Contêiner Spring IoC

O Spring IoC é o mecanismo para alcançar o desacoplamento entre as dependências dos objetos. Para atingir um acoplamento frouxo e vinculação dinâmica dos objetos em tempo de execução, as dependências dos objetos são injetadas por outros objetos montadores. O contêiner Spring IoC é o programa que injeta dependências em um objeto e o prepara para nosso uso. Já exploramos como podemos usar Injeção de Dependência Spring para implementar IoC em nossas aplicações. As classes do contêiner Spring IoC fazem parte dos pacotes org.springframework.beans e org.springframework.context. O contêiner Spring IoC nos oferece diferentes maneiras de desacoplar as dependências dos objetos. BeanFactory é a interface raiz do contêiner Spring IoC. ApplicationContext é a interface filha da interface BeanFactory que fornece recursos Spring AOP, i18n, etc. Algumas interfaces filhas úteis de ApplicationContext são ConfigurableApplicationContext e WebApplicationContext. O Spring Framework fornece várias classes de implementação úteis de ApplicationContext que podemos usar para obter o contexto Spring e, em seguida, o Spring Bean. Algumas das implementações úteis de ApplicationContext que usamos são;

  • AnnotationConfigApplicationContext: Se estamos usando o Spring em aplicativos Java autônomos e usando anotações para configuração, podemos usar isso para inicializar o contêiner e obter os objetos Bean.
  • ClassPathXmlApplicationContext: Se tivermos um arquivo de configuração xml de feijão de primavera em um aplicativo independente, então podemos usar esta classe para carregar o arquivo e obter o objeto de contêiner.
  • FileSystemXmlApplicationContext: Isso é semelhante ao ClassPathXmlApplicationContext, exceto que o arquivo de configuração xml pode ser carregado de qualquer lugar no sistema de arquivos.
  • AnnotationConfigWebApplicationContext e XmlWebApplicationContext para aplicativos da web.

Normalmente, se você estiver trabalhando em um aplicativo Spring MVC e seu aplicativo estiver configurado para usar o Spring Framework, o contêiner IoC do Spring é inicializado quando o aplicativo é iniciado e quando um feijão é solicitado, as dependências são injetadas automaticamente. No entanto, para um aplicativo independente, você precisa inicializar o contêiner em algum lugar do aplicativo e depois usá-lo para obter os feijões de primavera.

Feijão de Primavera

O Feijão de Primavera não é nada especial, qualquer objeto no framework Spring que inicializamos através do contêiner Spring é chamado de Feijão de Primavera. Qualquer classe Java POJO normal pode ser um Feijão de Primavera se estiver configurada para ser inicializada via contêiner, fornecendo informações de metadados de configuração.

Escopos de Feijão de Primavera

Existem cinco escopos definidos para Spring Beans.

  1. singleton – Apenas uma instância do bean será criada para cada contêiner. Este é o escopo padrão para os spring beans. Ao usar este escopo, certifique-se de que o bean não tenha variáveis de instância compartilhadas, caso contrário, poderá levar a problemas de inconsistência de dados.
  2. prototype – Uma nova instância será criada sempre que o bean for solicitado.
  3. request – Este é o mesmo escopo que o prototype, no entanto, é destinado a ser usado em aplicativos da web. Uma nova instância do bean será criada para cada solicitação HTTP.
  4. session – Um novo bean será criado para cada sessão HTTP pelo contêiner.
  5. global-session – Isso é usado para criar beans de sessão globais para aplicativos de portlet.

O Spring Framework é extensível e podemos criar nossos próprios escopos também. No entanto, na maioria das vezes, estamos bem com os escopos fornecidos pelo framework.

Configuração de Bean do Spring

O Spring Framework fornece três maneiras de configurar beans para serem usados na aplicação.

  1. Configuração Baseada em Anotações – Utilizando anotações como @Service ou @Component. Detalhes do escopo podem ser fornecidos com a anotação @Scope.
  2. Configuração Baseada em XML – Criando um arquivo XML de configuração Spring para configurar os beans. Se você estiver usando o framework Spring MVC, a configuração baseada em XML pode ser carregada automaticamente escrevendo algum código inicial no arquivo web.xml.
  3. Configuração Baseada em Java – A partir do Spring 3.0, podemos configurar beans do Spring usando programas Java. Algumas anotações importantes usadas para a configuração baseada em Java são @Configuration, @ComponentScan e @Bean.

Projeto de Exemplo do Spring IoC e Spring Bean

Vamos analisar os diferentes aspectos do contêiner Spring IoC e das configurações de Spring Bean com um projeto simples em Spring. Para o meu exemplo, estou criando um projeto Spring MVC no Spring Tool Suite. Se você é novo no Spring Tool Suite e no Spring MVC, por favor, leia Tutorial do Spring MVC com o Spring Tool Suite. A estrutura final do projeto parece com a imagem abaixo. Vamos examinar os diferentes componentes do projeto Spring IoC e Spring Bean um por um.

Configuração de Spring Bean Baseada em XML

MyBean é uma classe Java POJO simples.

package com.journaldev.spring.beans;

public class MyBean {

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

Arquivo XML de Configuração do Spring

Código do 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>

Observe que MyBean é configurado usando o elemento bean com o escopo como singleton.

Configuração de Spring Bean Baseada em Anotações

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;
	}
	
}

MyAnnotatedBean está configurado usando @Service e o escopo é definido como Requisição.

Classe Controladora Spring IoC

A classe HomeController irá lidar com as requisições HTTP para a página inicial da aplicação. Injetaremos nossos beans do Spring nesta classe de controladora através do contêiner 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";
	}
	
}

Descritor de Implantação

Precisamos configurar nossa aplicação para o Spring Framework para que os metadados de configuração sejam carregados e o contexto seja inicializado.

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

Quase toda a configuração acima é código de boilerplate gerado automaticamente pela ferramenta STS.

Execute a Aplicação de Exemplo de Bean Spring IoC

Agora, quando você lançar a aplicação web, a página inicial será carregada e no console os seguintes logs serão impressos quando você atualizar a página várias vezes.

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

Notice que MyBean está configurado para ser um singleton, então o contêiner está sempre retornando a mesma instância e o hashcode é sempre o mesmo. Da mesma forma, para cada solicitação, uma nova instância de MyAnnotatedBean é criada com hashcode diferente.

Configuração de Bean Spring Baseada em Java

Para aplicativos independentes, podemos usar configuração baseada em anotações, bem como configuração baseada em XML. O único requisito é inicializar o contexto em algum lugar do programa antes de usá-lo.

package com.journaldev.spring.main;

import java.util.Date;

public class MyService {

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

MyService é uma classe Java simples com alguns métodos.

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();
	}
}

A classe de configuração baseada em anotações que será usada para inicializar o contêiner 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

Se você estiver procurando por configuração baseada em XML, basta criar o arquivo de configuração XML do Spring e, em seguida, inicializar o contexto com o seguinte trecho de código.

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

Isso é tudo para o exemplo de tutorial do Spring IoC, Escopos de Bean Spring e Detalhes de Configuração. Faça o download do projeto de exemplo Spring IoC e Spring Bean no link abaixo e experimente para uma melhor compreensão.

Download do Projeto Spring Beans

Referência: Página Spring.IO para IOC

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