CodeGym /Blogue Java /Random-PT /Spring para pessoas preguiçosas Fundação, conceitos básic...
John Squirrels
Nível 41
San Francisco

Spring para pessoas preguiçosas Fundação, conceitos básicos e exemplos com código. Parte 2

Publicado no grupo Random-PT
No artigo anterior , expliquei brevemente o que é Spring e o que são beans e contexto. Agora é hora de experimentá-lo. Farei isso usando o IntelliJ IDEA Enterprise Edition. Mas todos os meus exemplos também devem funcionar no IntelliJ IDEA Community Edition gratuito. Nas capturas de tela, se você perceber que tenho alguma janela que você não tem, não se preocupe — não é importante para este projeto :) Spring para pessoas preguiçosas Fundação, conceitos básicos e exemplos com código.  Parte 2 - 1Primeiro, crie um projeto Maven vazio. Eu mostrei como fazer isso no artigo neste link . Leia até as palavras " É hora de convertermos nosso projeto Maven em um projeto da web. " — depois disso, o artigo mostra como fazer um projeto da web, mas não precisamos disso agora. No arquivo src/main/javapasta, crie um pacote (no meu caso, eu chamei de " en.codegym.info.fatfaggy.animals. Você pode chamá-lo do que quiser. Só não se esqueça de substituir o nome do meu pacote pelo nome do seu pacote em todos os lugares certos. Agora crie a Mainclasse e adicione um método

public static void main(String[] args) {
    ...
}
Depois disso, abra o arquivo pom.xml e adicione a dependenciesseção. Agora vá para o repositório Maven e encontre o contexto Spring para a versão estável mais recente. Coloque o que encontramos na dependenciesseção. Descrevi esse processo com mais detalhes neste outro artigo do CodeGym (consulte a seção " Conectando dependências no Maven "). Então o próprio Maven encontrará e baixará as dependências necessárias. No final, você deve obter algo assim: Spring para pessoas preguiçosas Fundação, conceitos básicos e exemplos com código.  Parte 2 - 2Na janela à esquerda, você pode ver a estrutura do projeto com o pacote e a Mainclasse. A janela do meio mostra como o pom.xml parece para mim. Eu também adicionei propriedadesseção para ele. Esta seção informa ao Maven qual versão do Java estou usando em meus arquivos de origem e qual versão compilar. Isso é apenas para que o IDEA não me avise que estou usando uma versão antiga do Java. Isso é opcional :) A janela da direita deixa claro que, embora tenhamos conectado apenas o módulo spring-context, ele puxou automaticamente os módulos spring-core, spring-beans, spring-aop e spring-expression. Poderíamos ter conectado cada módulo separadamente, escrevendo uma dependência para cada módulo com a versão explícita no arquivo pom.xml, mas por enquanto estamos satisfeitos com as coisas como estão. Agora crie o entitiespacote e crie 3 classes nele: Cat, Dog, Parrot. Vamos dar um nome a cada animal (private String name— você pode codificar alguns valores lá). Os getters/setters são públicos. Agora passamos para a Mainclasse e o main()método, e escrevemos algo assim:

public static void main(String[] args) {
	// Create an empty Spring context that will look for its own beans based on the annotations in the specified package
	ApplicationContext context = 
		new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.entities");

	Cat cat = context.getBean(Cat.class);
	Dog dog = (Dog) context.getBean("dog");
	Parrot parrot = context.getBean("parrot-polly", Parrot.class);

	System.out.println(cat.getName());
	System.out.println(dog.getName());
	System.out.println(parrot.getName());
}
Primeiro, criamos um objeto de contexto, informando ao construtor em qual pacote procurar para encontrar os beans. Em outras palavras, o Spring examinará esse pacote e tentará encontrar classes marcadas com anotações especiais que indiquem que são beans. Em seguida, ele cria os objetos dessas classes e os coloca no contexto. Depois disso, obtemos um gato desse contexto. Chamamos o objeto de contexto para nos fornecer um bean (objeto), indicando a classe do objeto que queremos (aliás, também podemos especificar interfaces, não apenas classes). Depois disso, o Spring retorna um objeto da classe solicitada, que salvamos em uma variável. Em seguida, pedimos a Spring que nos traga um feijão chamado "cachorro". Quando o Spring cria umDogobjeto, ele dá ao objeto um nome padrão (a menos que o bean criado tenha um nome atribuído explicitamente), que é o nome da classe, mas com uma letra minúscula inicial. Neste caso, nossa classe se chama Dog, então o nome do bean é be "dog". Se precisássemos de um BufferedReaderobjeto lá, o Spring o nomearia "bufferedReader". E como o Java não pode ter 100% de certeza de qual classe queremos, ele retorna um Objectobjeto, que então convertemos manualmente no tipo desejado, ou sejaDog. A opção onde a classe é indicada explicitamente é mais conveniente. A terceira opção é obter um bean pelo nome da classe e pelo nome do bean. É possível que o contexto tenha vários beans de uma única classe. Para indicar o bean específico de que precisamos, indicamos seu nome. Como também indicamos explicitamente a classe aqui, não precisamos mais executar uma conversão. IMPORTANTE!Se o Spring encontrar vários beans que correspondam aos nossos requisitos, ele não poderá determinar qual bean nos fornecer, então lançará uma exceção. Portanto, para evitar essa situação, você deve tentar ser o mais específico possível ao informar ao Spring qual bean você precisa. Se o Spring pesquisar seu contexto e não encontrar um único bean que corresponda aos nossos requisitos, ele também lançará uma exceção. Por fim, simplesmente exibimos os nomes de nossos animais para verificar se realmente conseguimos os objetos de que precisamos. Mas se executarmos o programa agora, veremos que o Spring está infeliz — ele não consegue encontrar os animais de que precisamos em seu contexto. Isso ocorre porque ele não criou esses beans. Como eu disse anteriormente, quando o Spring verifica as classes, ele procura por suas próprias anotações do Spring. E se o Spring não encontrar essas anotações, então não Não pense que essas classes correspondem aos beans que ele precisa criar. Corrigir isso requer simplesmente adicionar o@Componentanotação na frente de cada uma de nossas classes de animais.

@Component
public class Cat {
	private String name = "Oscar";
	...
}
Mas há mais. Se precisarmos dizer explicitamente ao Spring que o bean para esta classe deve ter um nome específico, indicamos o nome entre parênteses após a anotação. Por exemplo, para dizer ao Spring para dar o nome " parrot-polly" ao bean papagaio, que é o nome que usaremos para obter esse papagaio no mainmétodo, devemos fazer algo assim:

@Component("parrot-polly")
public class Parrot {
	private String name = "Polly";
	...
}
Este é o objetivo da configuração automática . Você escreve suas classes, marca-as com as anotações necessárias e informa ao Spring o pacote que contém suas classes. Este é o pacote que o framework irá percorrer para encontrar anotações e criar objetos dessas classes. A propósito, o Spring não procura apenas @Componentanotações, mas também todas as outras anotações que herdam esta. Por exemplo, @Controller, @RestController, @Service, @Repositorye mais, que apresentaremos em artigos futuros. Agora tentaremos fazer a mesma coisa usando a configuração baseada em Java . Para começar, remova o@Componentanotações de nossas aulas. Para tornar as coisas mais desafiadoras, imagine que não escrevemos essas classes, então não podemos modificá-las facilmente, o que significa que não podemos adicionar anotações. É como se essas classes fossem empacotadas em alguma biblioteca. Nesse caso, não temos como editar essas classes para que sejam reconhecidas pelo Spring. Mas precisamos de objetos dessas classes! Aqui precisamos de configuração baseada em Java para criar os objetos. Para começar, crie um pacote com um nome como configs. Neste pacote, crie uma classe Java comum, algo como MyConfig, e marque-a com a @Configurationanotação.

@Configuration
public class MyConfig {
}
Agora precisamos ajustar o main()método, mudando a forma como criamos o contexto. Podemos indicar explicitamente qual classe tem nossa configuração:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Se temos várias classes diferentes que criam beans e queremos conectar vários deles simultaneamente, basta indicarmos todos ali, separados por vírgulas:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
E se temos muitos deles e queremos conectá-los todos simultaneamente, simplesmente indicamos o nome do pacote em que estão contidos:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
Nesse caso, o Spring irá percorrer o pacote e encontrar todas as classes marcadas com a @Configurationanotação. Bem, e se tivermos um programa realmente grande onde as configurações são divididas em diferentes pacotes, simplesmente indicamos uma lista delimitada por vírgulas de nomes dos pacotes que contêm as configurações:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.database.configs",
		"en.codegym.info.fatfaggy.animals.root.configs",
		"en.codegym.info.fatfaggy.animals.web.configs");
Ou o nome de um pacote comum a todos:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
Você pode fazer como quiser, mas me parece que a primeira opção, que simplesmente indica uma aula com as configurações, é a que mais se adequa ao nosso programa. Ao criar um contexto, o Spring procura as classes marcadas com a @Configurationanotação e criará seus próprios objetos dessas classes. Ele tenta chamar métodos marcados com a @Beananotação, o que significa que esses métodos retornam beans (objetos) que o Spring adicionará ao contexto. E agora criaremos beans para gato, cachorro e papagaio em nossa classe com configuração baseada em Java. Isso é bem simples de fazer:

@Bean
public Cat getCat() {
	return new Cat();
}
Aqui, criamos manualmente nosso gato e o entregamos ao Spring, que mantém nosso objeto em seu contexto. Como não demos explicitamente um nome ao nosso bean, o Spring dará a ele o mesmo nome do método. No nosso caso, o cat bean será chamado de " getCat". Mas como usamos a classe, não o nome, para obter o cat bean no mainmétodo, o nome do bean não é importante para nós. Da mesma forma, crie um dog bean, lembrando que o Spring dará o nome do método ao bean. Para nomear explicitamente nosso feijão papagaio, simplesmente indicamos seu nome entre parênteses após a @Beananotação:

@Bean("parrot-polly")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Como você pode ver, aqui indiquei um Objecttipo de retorno e dei um nome arbitrário ao método. Isso não afeta o nome do bean, porque especificamos explicitamente o nome aqui. Ainda assim, é melhor indicar um valor de retorno e um nome de método mais ou menos significativos. Faça isso apenas para fazer um favor a si mesmo quando reabrir o projeto em um ano. :) Agora considere a situação em que precisamos de um bean para criar outro bean . Por exemplo, suponha que queremos que o nome do gato no feijão de gato seja o nome do papagaio mais a string "-killer". Sem problemas!

@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Aqui o Spring verá que para criar este bean, o framework precisa passar no bean parrot criado anteriormente. Consequentemente, ele organizará a cadeia necessária de chamadas de método: primeiro, o método de criação de papagaio é chamado e, em seguida, o framework passa o novo papagaio para o método de criação de gato. Aqui é onde a injeção de dependência entra em jogo: o próprio Spring passa o bean papagaio necessário para o nosso método. Se o IDEA ficar chateado com a parrotvariável, não se esqueça de alterar o tipo de retorno do método de criação do papagaio de Objectpara Parrot. Além disso, a configuração baseada em Java permite executar absolutamente qualquer código Javaem seus métodos de criação de bean. Você realmente pode fazer qualquer coisa: criar outros objetos auxiliares, chamar quaisquer outros métodos, mesmo aqueles não marcados com anotações do Spring, criar loops, condições booleanas — o que vier à sua mente! Nem tudo é possível com a configuração automática e muito menos com a configuração XML. Agora vamos considerar um problema um pouco mais divertido. Polimorfismo e interfaces :) Vamos criar uma WeekDayinterface e criar 7 classes que implementam essa interface: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Daremos à interface um String getWeekDayName()método, que retornará o nome do dia da semana para a classe correspondente. Em outras palavras, a Mondayclasse retornará "Monday", etc. Ao iniciar o aplicativo, suponha que nossa tarefa seja colocar um bean correspondente ao dia da semana atual no contexto. Não beans para todas as classes que implementam a interface — apenas um bean de que precisamos. Você WeekDaypode faça isso mais ou menos assim:

@Bean
public WeekDay getDay() {
	DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
	switch (dayOfWeek) {
		case MONDAY: return new Monday();
		case TUESDAY: return new Tuesday();
		case WEDNESDAY: return new Wednesday();
		case THURSDAY: return new Thursday();
		case FRIDAY: return new Friday();
		case SATURDAY: return new Saturday();
		default: return new Sunday();
	}
}
Aqui o tipo de retorno é a nossa interface. O método retorna um objeto bona fide de uma das classes que implementam a interface, dependendo do dia da semana atual. Agora podemos fazer o seguinte no main()método:

WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
Para mim, o programa me diz que é domingo :) Tenho certeza de que, se eu executar o programa amanhã, o contexto conterá um objeto completamente diferente. Observe que estamos obtendo o bean simplesmente usando a interface: context.getBean(WeekDay.class). O Spring procurará em seu contexto o bean que implementa a interface e o retornará. Acontece que nossa WeekDayvariável termina com um objeto de domingo, e o conceito familiar de polimorfismo se aplica à medida que trabalhamos com essa variável. :) Agora, algumas palavras sobre a abordagem combinada , na qual alguns beans são criados automaticamente pelo Spring, alguns escaneando pacotes em busca de classes com a @Componentanotação e outros por configuração baseada em Java. Ao considerarmos isso, retornaremos à versão original, onde o Cat, DogeParrotas aulas foram marcadas com a @Componentanotação. Suponha que queremos criar beans para nossos animais fazendo com que o Spring escaneie automaticamente o entitiespacote, mas também queremos criar um bean com o dia da semana, como acabamos de fazer. Basta adicionar a @ComponentScananotação no nível da MyConfigclasse, que indicamos ao criar o contexto em main(), e indicar entre parênteses o pacote que precisa ser escaneado e criar automaticamente os beans das classes necessárias:

@Configuration
@ComponentScan("en.codegym.info.fatfaggy.animals.entities")
public class MyConfig {
	@Bean
	public WeekDay getDay() {
		DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
		switch (dayOfWeek) {
			case MONDAY: return new Monday();
			case TUESDAY: return new Tuesday();
			case WEDNESDAY: return new Wednesday();
			case THURSDAY: return new Thursday();
			case FRIDAY: return new Friday();
			case SATURDAY: return new Saturday();
			default: return new Sunday();
		}
	}
}
Ao criar o contexto, o Spring percebe que precisa processar a MyConfigclasse. Ele entra na classe e vê que precisa escanear o en.codegym.info.fatfaggy.animals.entitiespacote " " e criar beans dessas classes, após o que executa o método MyConfigda classe getDay()e adiciona um WeekDaybean ao contexto. No main()método, agora temos acesso a todos os beans de que precisamos: tanto objetos animais quanto um bean com o dia da semana. Se você precisar fazer com que o Spring também pegue alguns arquivos de configuração XML, você pode fazer sua própria pesquisa na web para encontrar uma explicação :) Resumo:
  • Tente usar a configuração automática
  • Durante a configuração automática, indique o nome do pacote que contém as classes cujos beans devem ser criados
  • Essas classes são marcadas com a @Componentanotação
  • O Spring percorre todas essas classes, cria objetos e os coloca no contexto;
  • Se a configuração automática não nos convém por algum motivo, usamos a configuração baseada em Java
  • Nesse caso, criamos uma classe Java comum cujos métodos retornam os objetos de que precisamos. Marcamos esta classe com a @Configurationanotação se formos verificar o pacote inteiro em vez de indicar uma classe específica com a configuração ao criar o contexto
  • Os métodos desta classe que retornam beans são marcados com a @Beananotação
  • Se quisermos ativar a verificação automática ao usar a configuração baseada em Java, usamos a @ComponentScananotação.
Se este artigo foi totalmente confuso, tente lê-lo em alguns dias. Ou se você estiver em um dos níveis iniciais do CodeGym, pode ser um pouco cedo para você estudar o Spring. Você sempre pode retornar a este artigo um pouco mais tarde, quando se sentir mais confiante em suas habilidades de programação Java. Se tudo estiver claro, então você pode tentar converter algum projeto de estimação seu para o Spring :) Se algumas coisas estiverem claras, mas outras não, por favor, deixe um comentário :) Deixe-me saber suas sugestões e críticas, se eu der errado em algum lugar ou escrevi alguma bobagem :) No próximo artigo, mergulharemos abruptamente em spring-web-mvc e criaremos um aplicativo da web simples usando Spring.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION