JavaRush /Blogue Java /Random-PT /A primavera é para os preguiçosos. Fundamentos, conceitos...
Стас Пасинков
Nível 26
Киев

A primavera é para os preguiçosos. Fundamentos, conceitos básicos e exemplos com código. Parte 2

Publicado no grupo Random-PT
No último artigo , expliquei resumidamente o que é spring, o que são bins e contexto. Agora é hora de experimentar como tudo funciona. A primavera é para os preguiçosos.  Fundamentos, conceitos básicos e exemplos com código.  Parte 2 - 1Eu mesmo farei isso no Intellij Idea Enterprise Edition. Mas todos os meus exemplos também devem funcionar no Intellij Idea Community Edition gratuito. Só se você vir nas capturas de tela que tenho algum tipo de janela que você não tem, não se preocupe, não é crítico para este projeto :) Primeiro, vamos criar um projeto Maven vazio. Mostrei como fazer isso no artigo (leia até as palavras “ É hora de transformar nosso projeto maven em um projeto web. ”, depois disso já mostra como criar um projeto web, e não precisamos disso agora) Vamos criá-lo na pasta src/main /java é algum pacote (no meu caso chamei de “ ru.javarush.info.fatfaggy.animals”, você pode nomear como quiser, só não esqueça de substituí-lo pelo seu nome nos lugares certos). E vamos criar uma classe Mainna qual faremos um método
public static void main(String[] args) {
    ...
}
Em seguida, abra o arquivo pom.xml e adicione uma seção lá dependencies. Agora vamos para o repositório Maven e procuramos o contexto de primavera da versão estável mais recente e colamos o que obtivemos na seção dependencies. Descrevi esse processo com mais detalhes neste artigo (veja a seção " Conectando dependências no Maven "). Então o próprio Maven encontrará e baixará as dependências necessárias e, no final, você deverá obter algo assim:
A primavera é para os preguiçosos.  Fundamentos, conceitos básicos e exemplos com código.  Parte 2 - 2
Na janela esquerda você pode ver a estrutura do projeto com o pacote e a classe Main. A janela do meio mostra a aparência do meu pom.xml. Também adicionei lá uma seção de propriedades , na qual indiquei ao Maven qual versão do Java eu ​​estava usando no código-fonte e em qual versão compilar. Isso é apenas para que eu não tenha a ideia de receber um aviso ao iniciar informando que uma versão antiga do Java está sendo usada. Você pode fazer isso, você não pode) Na janela da direita - você pode ver que embora tenhamos conectado apenas o contexto spring - ele adicionou automaticamente core, beans, aop e expression. Foi possível conectar cada módulo separadamente, registrando na memória uma dependência de cada um com indicação explícita da versão, mas por enquanto estamos satisfeitos com a opção como está agora. Agora vamos criar um pacote entities(entidades) e criar 3 classes nele: Cat, Dog, Parrot. Deixe cada animal ter um nome ( private String namevocê pode codificar alguns valores lá) e os getters/setters serão públicos. Agora vá para a aula Maine main()escreva algo assim no método:
public static void main(String[] args) {
	// create an empty spring context that will search for its beans by annotations in the specified package
	ApplicationContext context =
		new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.entities");

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

	System.out.println(cat.getName());
	System.out.println(dog.getName());
	System.out.println(parrot.getName());
}
Primeiro, criamos um objeto de contexto e, no construtor, damos a ele o nome do pacote que precisa ser verificado quanto à presença de beans. Ou seja, o Spring irá percorrer este pacote e tentar encontrar classes que estejam marcadas com anotações especiais que informem ao Spring que se trata de um bean. Depois disso ele cria objetos dessas classes e os coloca em seu contexto. Depois disso, obtemos um gato deste contexto. Ao abordar o objeto de contexto, pedimos que ele nos forneça um bean (objeto) e indique qual classe de objeto precisamos (aqui, aliás, você pode especificar não apenas classes, mas também interfaces). Depois disso, o Spring nos retorna um objeto desta classe, que salvamos em uma variável. Em seguida, pedimos a Spring que nos traga um feijão chamado “cachorro”. Quando o Spring cria um objeto de classe, Dogele lhe dará um nome padrão (se o nome do bean que está sendo criado não for especificado explicitamente), que é o nome da classe do objeto, apenas com uma letra minúscula. Portanto, como nossa classe se chama Dog, o nome desse feijão será “cachorro”. Se tivéssemos um objeto lá BufferedReader, o Spring daria a ele o nome padrão “bufferedReader”. E como neste caso (em Java) não há certeza exata de qual classe será esse objeto, ele simplesmente retorna uma determinada Object, que então convertemos manualmente para o tipo que precisamos Dog. A opção com indicação explícita da classe é mais conveniente. Bem, no terceiro caso, obtemos um bean por classe e nome. Pode simplesmente haver uma situação em que no contexto haverá vários beans da mesma classe, e para indicar qual bean específico precisamos, indicamos seu nome. Como também indicamos claramente a classe aqui, não precisamos mais lançar. Importante!Se descobrir que o Spring encontra vários beans de acordo com os requisitos que especificamos para ele, ele não será capaz de determinar qual bean nos fornecer e lançará uma exceção. Portanto, procure indicar a ele com a maior precisão possível qual lixeira você precisa, para que tais situações não surjam. Se o Spring não encontrar um único bean em seu contexto de acordo com suas condições, ele também lançará uma exceção. Bem, então simplesmente exibimos os nomes dos nossos animais na tela para ter certeza de que esses são exatamente os objetos de que precisamos. Mas se executarmos o programa agora, veremos que Spring está jurando que não consegue encontrar os animais de que necessitamos no seu contexto. Isso aconteceu porque ele não criou esses feijões. Como eu já disse, quando o Spring verifica as classes, ele procura por “suas” anotações do Spring ali. E se não encontrar, então não percebe essas classes como aquelas cujos beans ele precisa criar. Para corrigir isso, basta adicionar uma anotação @Componentna frente da classe em nossas classes de animais.
@Component
public class Cat {
	private String name = "Barsik";
	...
}
Mas isso não é tudo. Se precisarmos indicar explicitamente ao Spring que o bean desta classe deve ter um nome específico, este nome pode ser indicado entre parênteses após a anotação. Por exemplo, para que Spring dê o nome que precisamos ao parrot-keshafeijão-papagaio, do qual mainmais tarde receberemos este papagaio, precisamos fazer algo assim:
@Component("parrot-kesha")
public class Parrot {
	private String name = "Kesha";
	...
}
Este é o objetivo da configuração automática . Você escreve suas classes, marca-as com as anotações necessárias e indica ao Spring um pacote com suas classes, por onde ele passa, procura anotações e cria objetos dessas classes. A propósito, o Spring irá pesquisar não apenas as anotações @Component, mas também todas as outras anotações que forem herdadas desta. Por exemplo, @Controller, @RestController, @Servicee @Repositoryoutros, que conheceremos em artigos futuros. Agora vamos tentar fazer o mesmo, mas usando configuração java . Primeiro, vamos remover anotações @Componentde nossas aulas. Para complicar a tarefa, vamos imaginar que estas não são nossas próprias classes escritas, que podemos facilmente modificar, adicionar algo, incluindo anotações. É como se essas aulas estivessem guardadas em alguma biblioteca. Neste caso, não podemos editar essas classes de forma alguma para que sejam aceitas até a primavera. Mas precisamos de objetos dessas classes! Aqui precisaremos da configuração java para criar tais objetos. Para começar, vamos criar um pacote, por exemplo configs, e nele - uma classe Java normal, por exemplo, MyConfige marcá-lo com uma anotação@Configuration
@Configuration
public class MyConfig {
}
Agora precisamos ajustar um pouco main()a forma como criamos o contexto no método. Podemos especificar diretamente nossa classe com configuração:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Se tivermos várias classes diferentes onde criamos beans e quisermos conectar vários deles ao mesmo tempo, simplesmente os indicamos separados por vírgulas:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Bem, se tivermos muitos deles e quisermos conectá-los todos de uma vez, simplesmente indicamos aqui o nome do pacote em que os temos:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.configs");
Neste caso, o Spring irá percorrer este pacote e encontrar todas as classes que estão marcadas com a anotação @Configuration. Bom, caso tenhamos um programa muito grande onde as configurações estão divididas em pacotes diferentes, simplesmente indicamos os nomes dos pacotes com as configurações separadas por vírgulas:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.database.configs",
		"ru.javarush.info.fatfaggy.animals.root.configs",
		"ru.javarush.info.fatfaggy.animals.web.configs");
Bom, ou o nome de um pacote mais comum a todos eles:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals");
Você pode fazer como quiser, mas me parece que a primeira opção, onde você simplesmente especifica uma classe com configurações, será mais adequada ao nosso programa. Ao criar um contexto, o Spring irá procurar aquelas classes que estão marcadas com a anotação @Configuratione criar ele mesmo objetos dessas classes. Depois disso ele tentará chamar métodos nessas classes que estão marcadas com a anotação @Bean, o que significa que tais métodos retornarão beans (objetos) que ele já colocou em seu contexto. Bem, agora vamos criar feijões gato, cachorro e papagaio em nossa classe com configuração java. Isso é feito de forma bastante simples:
@Bean
public Cat getCat() {
	return new Cat();
}
Acontece que nós mesmos criamos manualmente nosso gato e o entregamos ao Spring, e ele já colocou esse nosso objeto em seu contexto. Como não especificamos explicitamente o nome do nosso bean, o Spring dará ao bean o mesmo nome do método. No nosso caso, o feijão-gato terá o nome " getCat". Mas como em main-e ainda obtemos o gato não pelo nome, mas pela classe, nesse caso o nome dessa lixeira não é importante para nós. Faça um feijão com um cachorro da mesma maneira, mas lembre-se de que Spring nomeará esse feijão pelo nome do método. Para nomear explicitamente nosso bean com o papagaio, basta indicar seu nome entre parênteses após a anotação @Bean:
@Bean("parrot-kesha")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Como você pode ver, aqui indiquei o tipo do valor de retorno Objecte chamei o método de qualquer coisa. Isso não afeta o nome do bean de forma alguma porque o definimos explicitamente aqui. Mas é melhor indicar o tipo de valor de retorno e o nome do método não do nada, mas de forma mais ou menos clara. Até para você, quando abrir este projeto em um ano. :) Agora vamos considerar uma situação onde para criar um bean precisamos usar outro bean . Por exemplo, queremos que o nome do gato no feijão de gato consista no nome do papagaio e na 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 antes de criar este bean, ele precisará transferir o bean papagaio já criado para cá. Portanto, ele construirá uma cadeia de chamadas para nossos métodos para que o método de criação de um papagaio seja chamado primeiro e depois passe esse papagaio para o método de criação de um gato. É aqui que a coisa chamada injeção de dependência funcionou : o próprio Spring passou o parrot bean necessário para o nosso método. Se a ideia reclamar de uma variável parrot, não esqueça de alterar o tipo de retorno no método de criação de um papagaio de Objectpara Parrot. Além disso, a configuração Java permite executar absolutamente qualquer código Java em métodos de criação de beans. Você realmente pode fazer qualquer coisa: criar outros objetos auxiliares, chamar quaisquer outros métodos, mesmo aqueles não marcados com anotações de primavera, fazer loops, condições - o que vier à mente! Tudo isso não pode ser conseguido usando configuração automática, muito menos usando configurações xml. Agora vamos examinar um problema mais divertido. Com polimorfismo e interfaces :) Vamos criar uma interface WeekDaye criar 7 classes que implementariam essa interface: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Vamos criar um método na interface String getWeekDayName()que retorne o nome do dia da semana da classe correspondente. Ou seja, a classe Mondayretornaria " monday", etc. Digamos que a tarefa ao iniciar nossa aplicação seja colocar um bean no contexto que corresponderia ao dia da semana atual. Nem todos os beans de todas as classes que implementam WeekDaya interface, mas apenas aquele que precisamos. Isso pode ser feito algo 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 valor de retorno é nossa interface, e o método retorna objetos reais das classes de implementação da interface dependendo do dia da semana atual. Agora no método main()podemos fazer isso:
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("It's " + weekDay.getWeekDayName() + " today!");
Ele me disse que hoje é domingo :) Tenho certeza que se eu executar o programa amanhã, um objeto completamente diferente aparecerá no contexto. Observe que aqui obtemos o bean simplesmente pela interface: context.getBean(WeekDay.class). O Spring procurará em seu contexto qual de seus beans implementa tal interface e a retornará. Pois bem, então acontece que WeekDayexiste um objeto do tipo em uma variável do tipo Sunday, e o polimorfismo, já familiar a todos nós, começa ao trabalhar com essa variável. :) E algumas palavras sobre a abordagem combinada , onde alguns dos beans são criados pelo próprio Spring, usando varredura de pacotes em busca de classes com anotação @Component, e alguns outros beans são criados usando a configuração java. Para fazer isso, vamos voltar à versão original, quando as classes e Cateram marcadas com uma anotação . Digamos que queremos criar lixeiras para nossos animais usando a digitalização automática da embalagem até a primavera, mas criar uma lixeira com o dia da semana como acabamos de fazer. Tudo que você precisa fazer é adicionar no nível da classe , que especificamos ao criar o contexto na -ésima anotação , e indicar entre colchetes o pacote que precisa ser verificado e os beans das classes necessárias criados automaticamente: DogParrot@ComponententitiesMyConfigmain@ComponentScan
@Configuration
@ComponentScan("ru.javarush.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();
		}
	}
}
Acontece que ao criar um contexto, o Spring vê que precisa processar a classe MyConfig. Ele entra e vê que precisa escanear o pacote " ru.javarush.info.fatfaggy.animals.entities" e criar beans dessas classes, após o que ele executa um método getDay()da classe MyConfige adiciona um bean do tipo WeekDayao seu contexto. No método, main()agora temos acesso a todos os feijões que precisamos: tanto os objetos animais quanto o feijão do dia da semana. Como garantir que o Spring também obtenha algumas configurações xml - pesquise você mesmo na Internet se precisar :) Resumo:
  • tente usar a configuração automática;
  • durante a configuração automática indicamos o nome do pacote que contém as classes cujos beans precisam ser criados;
  • tais classes são marcadas com uma anotação@Component;
  • spring passa por todas essas classes e cria seus objetos e os coloca no contexto;
  • se a configuração automática não nos convém por algum motivo, usamos a configuração java;
  • neste caso, criamos uma classe Java regular cujos métodos retornarão os objetos que precisamos e marcaremos tal classe com uma anotação @Configurationcaso varremos o pacote inteiro em vez de especificar uma classe específica com configuração ao criar o contexto;
  • os métodos desta classe que retornam beans são marcados com a anotação @Bean;
  • se quisermos ativar a verificação automática ao usar a configuração java, usamos a anotação @ComponentScan.
Se nada estiver claro, tente ler este artigo em alguns dias. Bem, ou se você está nos níveis iniciais de Javarash, talvez seja um pouco cedo para aprender a primavera. Você sempre pode retornar a este artigo um pouco mais tarde, quando se sentir mais confiante para programar em Java. Se tudo estiver claro, você pode tentar transferir alguns de seus projetos favoritos para o Spring :) Se algo estiver claro, mas algo não estiver muito claro, comente :) Também há sugestões e comentários se eu pisei em algum lugar ou escrevi algo estúpido ) No próximo artigo, nos aprofundaremos no spring-web-mvc e criaremos um aplicativo web simples usando spring.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION