
O Spring Framework é um dos mais complicados para entender e aprender. A maioria dos desenvolvedores aprende devagar, através de tarefas práticas e do google. Essa abordagem não é eficaz, pois não fornece uma imagem completa e, ao mesmo tempo, é cara.
Gostaria de oferecer a você uma abordagem fundamentalmente nova para o estudo da primavera. Consiste no fato de que uma pessoa passa por uma série de tutoriais especialmente preparados e implementa independentemente o funcionamento da primavera. A peculiaridade dessa abordagem é que, além de uma compreensão 100% dos aspectos estudados do Spring, também oferece um grande aumento no Java Core (anotações, reflexão, arquivos, genéricos).
O artigo fornecerá uma experiência inesquecível e fará você se sentir como um desenvolvedor Pivotal. Passo a passo, você fará suas aulas se tornarem melhores e organizará seu ciclo de vida (o mesmo que em uma primavera real). As classes que você implementará são
BeanFactory ,
Component ,
Service ,
BeanPostProcessor ,
BeanNameAware ,
BeanFactoryAware ,
InitializingBean ,
PostConstruct ,
PreDestroy ,
DisposableBean ,
ApplicationContext ,
ApplicationListener ,
ContextClosedEvent .
Um pouco sobre você
Meu nome é Yaroslav e sou desenvolvedor Java com 4 anos de experiência. No momento, trabalho na EPAM Systems (SPB) e me aprofundo nas tecnologias que usamos. Muitas vezes tenho que lidar com a primavera, e vejo nela um meio-termo no qual você pode crescer (Java todo mundo sabe tão bem, e ferramentas e tecnologias específicas demais podem ir e vir).
Há alguns meses, passei na certificação Spring Professional v5.0 (sem fazer cursos). Depois disso, pensei em como ensinar outras pessoas a saltar. Infelizmente, no momento não existe uma metodologia de ensino eficaz. A maioria dos desenvolvedores tem uma idéia muito superficial da estrutura e seus recursos. Depurar as fontes da primavera é muito difícil e absolutamente não é eficaz do ponto de vista do treinamento (eu gostava disso). Faça 10 projetos? Sim, você pode aprofundar seu conhecimento em algum lugar e obter muita experiência prática, mas muito do que está “escondido” nunca será aberto antes de você. Leia Primavera em ação? Legal, mas caro no esforço. Eu trabalhei 40% (durante a preparação para a certificação), mas não foi fácil.
A única maneira de entender algo até o fim é desenvolvê-lo você mesmo. Recentemente, tive a ideia de que você pode liderar uma pessoa através de um tutorial interessante que supervisionará o desenvolvimento de sua estrutura de DI. Sua principal característica será que a API coincidirá com a API que está sendo estudada. A grandiosidade dessa abordagem é que, além de uma compreensão profunda (sem espaços) da primavera, uma pessoa terá uma enorme quantidade de experiência no Java Core. Francamente, eu próprio aprendi muitas coisas novas durante a preparação do artigo, tanto no Spring quanto no Java Core. Vamos começar a desenvolver!
Projeto do zero
Portanto, a primeira coisa a fazer é abrir seu IDE favorito e criar um projeto a partir do zero. Não conectaremos nenhum Maven ou qualquer biblioteca de terceiros. Nós nem vamos conectar as dependências do Spring. Nosso objetivo é desenvolver uma API que seja mais semelhante à API Spring e implementá-la.
Em um projeto limpo, crie 2 pacotes principais. O primeiro pacote é seu aplicativo (
com.kciray
) e a classe
Main.java
dentro dele. O segundo pacote é org.springframework. Sim, duplicaremos a estrutura do pacote da mola original, o nome de suas classes e seus métodos. Há um efeito tão interessante - quando você cria algo próprio, esse começa a parecer simples e compreensível. Então, quando você trabalha em grandes projetos, parece que tudo é criado lá com base na sua peça de trabalho. Essa abordagem pode ter um efeito muito positivo na compreensão do sistema como um todo, aprimorando-o, corrigindo bugs, resolvendo problemas e assim por diante.
Se você tiver algum problema, pode
fazer um projeto em funcionamento
aqui .
Crie um container
Para começar, defina a tarefa. Suponha que tenhamos 2 classes -
ProductFacade
e
PromotionService
. Agora imagine que você deseja conectar essas classes entre si, mas para que as próprias classes não se conheçam (Padrão DI). Precisamos de uma classe separada que gerencie todas essas classes e determine as dependências entre elas. Vamos chamar de contêiner. Vamos criar a classe
Container
... Embora não, espere! O Spring não possui uma única classe de contêiner. Temos muitas implementações de contêineres, e todas essas implementações podem ser divididas em 2 tipos - fábricas e contextos. A fábrica de caixas cria beans e os vincula (injeção de dependência, DI), e o contexto faz o mesmo, além de adicionar alguns recursos adicionais (por exemplo, internacionalizar mensagens). Mas como não precisamos dessas funções adicionais agora, trabalharemos com a fábrica de lixeiras.
Crie uma nova classe
BeanFactory
e coloque-a no pacote
org.springframework.beans.factory
. Deixe os
Map<String, Object> singletons
armazenados dentro dessa classe, na qual o
id
compartimento é mapeado para o próprio compartimento. Adicione a ele o
Object getBean(String beanName)
, que extrai os beans pelo identificador.
public class BeanFactory { private Map<String, Object> singletons = new HashMap(); public Object getBean(String beanName){ return singletons.get(beanName); } }
Observe que
BeanFactory
e
FactoryBean
são duas coisas diferentes. A primeira é a fábrica de lixeiras (contêiner) e a segunda é a fábrica de lixeiras, que fica dentro do contêiner e também produz caixas. Fábrica dentro da fábrica. Se você estiver confuso entre essas definições, lembre-se de que em inglês o segundo substantivo é o principal e o primeiro é algo como um adjetivo. Na
Fábrica de Feijão
, a palavra principal é a fábrica, e na Fábrica de
Feijão , o feijão.
Agora, crie as classes
ProductService
e
PromotionsService
.
ProductService
retornará o produto do banco de dados, mas antes disso você precisará verificar se há descontos (Promoções) aplicáveis a este produto. No comércio eletrônico, o trabalho com desconto geralmente é alocado para uma classe de serviço separada (e às vezes para um serviço da web de terceiros).
public class PromotionsService { } public class ProductService { private PromotionsService promotionsService; public PromotionsService getPromotionsService() { return promotionsService; } public void setPromotionsService(PromotionsService promotionsService) { this.promotionsService = promotionsService; } }
Agora precisamos fazer nosso contêiner (
BeanFactory
) detectar nossas classes, criá-las para nós e injetar uma na outra. Operações como o
new ProductService()
devem estar localizadas dentro do contêiner e feitas pelo desenvolvedor. Vamos usar a abordagem mais moderna (digitalização de classe e anotações). Para fazer isso, precisamos criar uma anotação
@Component
com as
@Component
(
org.springframework.beans.factory.stereotype
).
@Retention(RetentionPolicy.RUNTIME) public @interface Component { }
Por padrão, as anotações não são carregadas na memória enquanto o programa está em execução (
RetentionPolicy.CLASS
). Alteramos esse comportamento por meio de uma nova política de retenção (
RetentionPolicy.RUNTIME
).
Agora adicione
@Component
antes das classes
ProductService
e antes do
PromotionService
.
@Component public class ProductService {
Precisamos do
BeanFactory
escanear nosso pacote (
com.kciray
) e encontrar classes nele anotadas por
@Component
. Esta tarefa está longe de ser trivial. Não existe
uma solução pronta no Java Core, e teremos que fazer uma muleta. Milhares de aplicações de molas usam a digitalização de componentes nessa muleta. Você aprendeu a terrível verdade. Você terá que extrair os nomes de
ClassLoader
do
ClassLoader
e verificar
ClassLoader
eles terminam com ".class" ou não, e então criar seu nome completo e extrair objetos de classe!
Quero avisar imediatamente que haverá muitas exceções verificadas, portanto, esteja preparado para quebrá-las. Mas primeiro, vamos decidir o que queremos. Queremos adicionar um método especial ao
BeanFactory
e chamá-lo em
Main
:
Em seguida, precisamos obter o
ClassLoader
. Ele é responsável pelo carregamento de classes e é extraído de maneira simples:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Você provavelmente já percebeu que os pacotes são separados por um ponto e os arquivos por uma barra. Precisamos converter o caminho do lote para o caminho da pasta e obter algo como
List<URL>
(os caminhos no seu sistema de arquivos onde você pode procurar por arquivos de classe).
String path = basePackage.replace('.', '/');
Então espere um momento!
Enumeration<URL>
não é uma
List<URL>
. O que é isso tudo? Ah, horror, esse é o antigo progenitor do
Iterator
, disponível desde o Java 1.0. É com esse legado que devemos lidar. Se for possível percorrer o
Iterable
usando for (todas as coleções o implementam), no caso de
Enumeration
você precisará fazer um desvio de identificador, através de
while(resources.hasMoreElements())
e
nextElement()
. E, no entanto, não há como remover itens da coleção. Apenas 1996, apenas hardcore. Ah, sim, no Java 9 eles adicionaram o método
Enumeration.asIterator()
, para que você possa trabalhar com ele.
Vamos mais longe. Precisamos extrair as pastas e trabalhar com o conteúdo de cada uma delas. Converta o URL em um arquivo e obtenha seu nome. Deve-se notar aqui que não verificaremos pacotes aninhados para não complicar o código. Você pode complicar sua tarefa e fazer uma recursão, se desejar.
while (resources.hasMoreElements()) { URL resource = resources.nextElement(); File file = new File(resource.toURI()); for(File classFile : file.listFiles()){ String fileName = classFile.getName();
Em seguida, precisamos obter o nome do arquivo sem a extensão. No estaleiro em 2018, o Java desenvolveu o File I / O (NIO 2) por muitos anos, mas ainda não pode separar a extensão do nome do arquivo. Eu tenho que criar minha própria bicicleta, porque decidimos não usar bibliotecas de terceiros como o Apache Commons. Vamos usar o antigo avô como
lastIndexOf(".")
:
if(fileName.endsWith(".class")){ String className = fileName.substring(0, fileName.lastIndexOf(".")); }
Em seguida, podemos obter o objeto de classe usando o nome completo da classe (para isso chamamos de classe da classe
Class
):
Class classObject = Class.forName(basePackage + "." + className);
Ok, agora nossas aulas estão em nossas mãos. Além disso, resta apenas destacar entre eles aqueles que possuem a anotação
@Component
:
if(classObject.isAnnotationPresent(Component.class)){ System.out.println("Component: " + classObject); }
Corra e verifique. O console deve ser algo como isto:
Component: class com.kciray.ProductService Component: class com.kciray.PromotionsService
Agora precisamos criar nosso bean. Você precisa fazer algo como o
new ProductService()
, mas para cada bean, temos nossa própria classe. A reflexão em Java nos fornece uma solução universal (o construtor padrão é chamado):
Object instance = classObject.newInstance();
Em seguida, precisamos colocar esse bean nos
Map<String, Object> singletons
. Para fazer isso, selecione o nome do bean (seu ID). Em Java, chamamos variáveis como classes (apenas a primeira letra é minúscula). Essa abordagem também pode ser aplicada aos beans, porque o Spring é uma estrutura Java! Converta o nome da lixeira para que a primeira letra seja pequena e adicione-a ao mapa:
String beanName = className.substring(0, 1).toLowerCase() + className.substring(1); singletons.put(beanName, instance);
Agora verifique se tudo funciona. O contêiner deve criar beans e eles devem ser recuperados pelo nome. Observe que o nome do seu método
instantiate()
e o nome do método
classObject.newInstance();
tem uma raiz comum. Além disso,
instantiate()
faz parte do ciclo de vida do feijão. Em Java, tudo está interconectado!
Tente também implementar a anotação
org.springframework.beans.factory.stereotype.Service
. Ele executa exatamente a mesma função que o
@Component
, mas é chamado de maneira diferente. O ponto principal está no nome - você demonstra que a classe é um serviço, não apenas um componente. Isso é algo como digitação conceitual. Na certificação da primavera, houve a pergunta "Quais anotações são estereotipadas?" (dos listados). ” Portanto, anotações estereotipadas são aquelas que estão no pacote de
stereotype
.
Preencha as propriedades
Veja o diagrama abaixo, que mostra o início do ciclo de vida do feijão. O que fizemos antes disso é o Instantiate (criando beans através de
newInstance()
). O próximo passo é a injeção cruzada de feijão (injeção de dependência, é também a inversão de controle (IoC)). Você precisa examinar as propriedades dos beans e entender quais propriedades você precisa injetar. Se você chamar
productService.getPromotionsService()
, será
null
porque dependência ainda não adicionada.

Primeiro, crie o pacote
org.springframework.beans.factory.annotation
e adicione a anotação
@Autowired
. A idéia é sinalizar campos que são dependências com esta anotação.
@Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }
Em seguida, adicione-o à propriedade:
@Component public class ProductService { @Autowired PromotionsService promotionsService;
Agora precisamos ensinar nosso
BeanFactory
encontrar essas anotações e injetar dependências nelas. Adicione um método separado para isso e chame-o de
Main
:
public class BeanFactory {
Em seguida, precisamos apenas examinar todos os nossos compartimentos no mapa de
singletons
e, para cada compartimento, todos os seus campos (
object.getClass().getDeclaredFields()
retorna todos os campos, incluindo os privados). E verifique se o campo possui uma anotação
@Autowired
:
for (Object object : singletons.values()) { for (Field field : object.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { } } }
Em seguida, precisamos examinar todas as caixas mais uma vez e ver seu tipo - de repente, esse é o tipo que nossa lixeira quer usar por si mesma. Sim, temos um ciclo tridimensional!
for (Object dependency : singletons.values()) { if (dependency.getClass().equals(field.getType())) { } }
Além disso, quando encontramos o vício, precisamos injetá-lo. A primeira coisa que você pode pensar é escrever o campo
promotionsService
usando a reflexão diretamente. Mas a primavera não funciona assim. Afinal, se o campo tiver um modificador
private
, primeiro precisaremos defini-lo como
public
, depois escreva nosso valor e, em seguida, defina-
private
novamente como
private
(para manter a integridade). Parece uma muleta grande. Em vez de uma muleta grande, vamos fazer uma muleta pequena (formaremos o nome do levantador e o chamaremos):
String setterName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Agora execute seu projeto e certifique-se de que, ao chamar
productService.getPromotionsService()
vez de
null
, nosso bean seja retornado.
O que implementamos é a injeção por tipo. Também há uma injeção pelo nome (anotação
javax.annotation.Resource
). É diferente porque, em vez do tipo do campo, seu nome será extraído e, de acordo com ele - a dependência do mapa. Tudo é semelhante aqui, mesmo em algo mais simples. Eu recomendo que você experimente e crie seu próprio bean, injete-o com
@Resource
e estenda o método
populateProperties()
.
Apoiamos beans que sabem sobre seu nome

Há momentos em que você precisa colocar o nome dele dentro da lixeira. Essa necessidade não surge frequentemente, porque caixas, em essência, não devem saber um sobre o outro e que são caixas. Nas primeiras versões da primavera, foi assumido que o bean é um POJO (Plain Old Java Objec, o bom e antigo objeto Java) e toda a configuração é renderizada em arquivos XML e separada da implementação. Mas implementamos essa funcionalidade, pois a injeção de nome faz parte do ciclo de vida da lixeira.
Como sabemos qual bean quer saber qual é o nome dele e o que ele não quer? A primeira coisa que vem à mente é fazer uma nova anotação do tipo
@InjectName
e esculpir em campos do tipo String. Mas essa solução será muito geral e permitirá que você se atire várias vezes (coloque essa anotação em campos de tipos inapropriados (não String) ou tente inserir um nome em vários campos da mesma classe). Existe outra solução, mais precisa - para criar uma interface especial com um método de incubação. Todos os compartimentos que o implementam recebem seu nome. Crie a classe
BeanNameAware
no pacote
org.springframework.beans.factory
:
public interface BeanNameAware { void setBeanName(String name); }
Em seguida, permita que o nosso
PromotionsService
implemente:
@Component public class PromotionsService implements BeanNameAware { private String beanName; @Override public void setBeanName(String name) { beanName = name; } public String getBeanName() { return beanName; } }
E, finalmente, adicione um novo método à fábrica de feijão. Tudo é simples aqui - examinamos nosso bin-singleton, verificamos se o bin implementa nossa interface e chamamos o setter:
public void injectBeanNames(){ for (String name : singletons.keySet()) { Object bean = singletons.get(name); if(bean instanceof BeanNameAware){ ((BeanNameAware) bean).setBeanName(name); } } }
Execute e verifique se tudo funciona:
BeanFactory beanFactory = new BeanFactory(); beanFactory.instantiate("com.kciray"); beanFactory.populateProperties(); beanFactory.injectBeanNames();
Note-se que na primavera existem outras interfaces semelhantes. Eu recomendo que você implemente a interface
BeanFactoryAware , que permite que os beans recebam um link para a fábrica de beans. É implementado de maneira semelhante.
Inicializar Beans

Imagine que você tem uma situação em que precisa executar algum código após as dependências serem injetadas (as propriedades da bandeja são definidas). Em termos simples, precisamos dar à lixeira a capacidade de se inicializar. Como alternativa, podemos criar uma interface
InitializingBean
e colocar a assinatura do método
void afterPropertiesSet()
nela. A implementação desse mecanismo é exatamente a mesma apresentada para a interface
BeanNameAware
, portanto, a solução está sob o spoiler. Pratique e faça você mesmo em um minuto:
Solução de Inicialização do Bean Adicionando pós-processadores
Imagine-se no lugar dos primeiros desenvolvedores da primavera. Sua estrutura está crescendo e é muito popular entre os desenvolvedores; cartas são enviadas diariamente para o correio com solicitações para adicionar um ou outro recurso útil. Se, para cada um desses recursos, você adicionar sua própria interface e verificar o ciclo de vida do bean, ele (o ciclo de vida) ficará entupido com informações desnecessárias. Em vez disso, podemos criar uma interface universal que nos permita adicionar alguma lógica (absolutamente qualquer, esteja ela verificando anotações, substituindo a bandeja por outra, definindo algumas propriedades especiais e assim por diante).
Vamos pensar sobre o que é essa interface. Ele precisa fazer algum pós-processamento dos beans, portanto, pode ser chamado de BeanPostProcessor. Mas estamos diante de uma pergunta difícil - quando a lógica deve ser seguida? Afinal, podemos executá-lo antes da inicialização, mas podemos executá-lo depois. Para algumas tarefas, a primeira opção é melhor, para outras - a segunda ... Como ser?
Podemos ativar as duas opções ao mesmo tempo. Deixe um pós-processador transportar duas lógicas, dois métodos. Um é executado antes da inicialização (antes do método
afterPropertiesSet()
) e o outro depois. Agora, vamos pensar nos próprios métodos - quais parâmetros eles devem ter? Obviamente, o próprio
Object bean
(
Object bean
) deve estar lá. Por conveniência, além do bean, você pode passar o nome desse bean. Você se lembra que o próprio compartimento não sabe sobre o seu nome. E não queremos forçar todos os beans a implementar a interface BeanNameAware. Mas, no nível pós-processador, o nome do bean pode ser muito útil. Portanto, nós o adicionamos como o segundo parâmetro.
E o que o método deve retornar ao pós-processamento do bean? Vamos fazer com que ele devolva a lixeira. Isso nos dá uma super flexibilidade, porque em vez de uma lixeira, você pode colocar um objeto proxy que encerra suas chamadas (e adiciona segurança). Ou você pode retornar completamente outro objeto recriando a bandeja novamente. Os desenvolvedores têm uma grande liberdade de ação. Abaixo está a versão final da interface projetada:
package org.springframework.beans.factory.config; public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName); Object postProcessAfterInitialization(Object bean, String beanName); }
Em seguida, precisamos adicionar uma lista de processadores simples à nossa fábrica de beans e a capacidade de adicionar novos. Sim, este é um ArrayList regular.
Agora mude o método
initializeBeans
para levar em conta os pós-processadores:
public void initializeBeans() { for (String name : singletons.keySet()) { Object bean = singletons.get(name); for (BeanPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeforeInitialization(bean, name); } if (bean instanceof InitializingBean) { ((InitializingBean) bean).afterPropertiesSet(); } for (BeanPostProcessor postProcessor : postProcessors) { postProcessor.postProcessAfterInitialization(bean, name); } } }
Vamos criar um pequeno pós-processador que simplesmente rastreia as chamadas para o console e adicione-o à nossa fábrica de feijão:
public class CustomPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("---CustomPostProcessor Before " + beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("---CustomPostProcessor After " + beanName); return bean; } }
Agora execute e verifique se tudo funciona. Como tarefa de treinamento, crie um pós-processador que fornecerá a anotação
@PostConstruct (javax.annotation.PostConstruct)
. Ele fornece uma maneira alternativa de inicializar (enraizada em Java, não na primavera). Sua essência é que você coloca a anotação em algum método, e esse método será chamado ANTES da inicialização padrão da primavera (InitializingBean).
Certifique-se de criar todas as anotações e pacotes (mesmo javax.annotation) manualmente, não conecte as dependências! Isso ajudará você a ver a diferença entre o núcleo da mola e suas extensões (suporte a javax), e lembre-se disso. Isso manterá um estilo no futuro.
Você estará interessado no fato de que, em uma primavera real, a anotação @PostConstruct
é implementada dessa maneira, por meio do CommonAnnotationBeanPostProcessor do pós-processador. Mas não espie lá, escreva sua implementação.Por fim, recomendo que você adicione um método void close()
à classe BeanFactory
e elabore mais dois mecanismos. A primeira é uma anotação @PreDestroy (javax.annotation.PreDestroy)
, destinada a métodos que devem ser chamados quando o contêiner é fechado. O segundo é a interface org.springframework.beans.factory.DisposableBean
que contém o método void destroy()
. Todos os compartimentos executando esta interface terão a capacidade de se destruir (liberar recursos, por exemplo).@PreDestroy + DisposableBean Ciclo de vida completo do feijão
Por isso, implementamos o ciclo de vida completo da lixeira, em sua forma moderna. Espero que essa abordagem ajude você a se lembrar dela.Nosso contexto favorito
Os programadores costumam usar o termo contexto, mas nem todos entendem o que realmente significa. Agora vamos colocar tudo em ordem. Como observei no início do artigo, o contexto é a implementação do contêiner, assim como BeanFactory
. Mas, além das funções básicas (DI), ele ainda adiciona alguns recursos interessantes. Um desses recursos é o envio e o processamento de eventos entre os compartimentos.O artigo acabou sendo muito grande e o conteúdo começou a ser cortado, então coloquei as informações de contexto embaixo do spoiler.Percebemos o contexto.
org.springframework.context
,
ApplicationContext
.
BeanFactory
. ,
close()
.
public class ApplicationContext { private BeanFactory beanFactory = new BeanFactory(); public ApplicationContext(String basePackage) throws ReflectiveOperationException{ System.out.println("******Context is under construction******"); beanFactory.instantiate(basePackage); beanFactory.populateProperties(); beanFactory.injectBeanNames(); beanFactory.initializeBeans(); } public void close(){ beanFactory.close(); } }
Main
, , :
ApplicationContext applicationContext = new ApplicationContext("com.kciray"); applicationContext.close();
, .
close()
, « » - . , :
package org.springframework.context.event; public class ContextClosedEvent { }
ApplicationListener
, . , (
ApplicationListener<E>
). , Java-, . , , :
package org.springframework.context; public interface ApplicationListener<E>{ void onApplicationEvent(E event); }
ApplicationContext
.
close()
, , .
ApplicationListener<ContextClosedEvent>
,
onApplicationEvent(ContextClosedEvent)
. , ?
public void close(){ beanFactory.close(); for(Object bean : beanFactory.getSingletons().values()) { if (bean instanceof ApplicationListener) { } } }
Mas não. .
bean instanceof ApplicationListener<ContextClosedEvent>
. Java.
(type erasure) , <T> <Object>. , ? ,
ApplicationListener<ContextClosedEvent>
, ?
, , . , , , , :
for (Type type: bean.getClass().getGenericInterfaces()){ if(type instanceof ParameterizedType){ ParameterizedType parameterizedType = (ParameterizedType) type; } }
, , , — . , :
Type firstParameter = parameterizedType.getActualTypeArguments()[0]; if(firstParameter.equals(ContextClosedEvent.class)){ Method method = bean.getClass().getMethod("onApplicationEvent", ContextClosedEvent.class); method.invoke(bean, new ContextClosedEvent()); }
ApplicationListener:
@Service public class PromotionsService implements BeanNameAware, ApplicationListener<ContextClosedEvent> {
, Main , , :
Conclusão
Inicialmente, planejei este artigo para o Baeldung em inglês, mas depois pensei que o público do Habré poderia avaliar positivamente essa abordagem do treinamento. Se você gostou das minhas idéias, não deixe de apoiar o artigo. Se ela obtiver uma classificação superior a 30, prometo continuar. Ao escrever o artigo, tentei mostrar exatamente o conhecimento do Spring Core, que é mais frequentemente usado, e também com base no Guia de Estudo de Certificação do Core Spring 5.0 . No futuro, com a ajuda desses tutoriais, você poderá cobrir toda a certificação e tornar a primavera mais acessível para os desenvolvedores Java.Atualização 05/10/2018
Cartas constantemente me chegam com perguntas "e quando a continuação estamos esperando por ele". Mas não há tempo, e outros projetos pessoais são uma prioridade. No entanto, se um de vocês realmente gostou da ideia, pode estudar a seção estreita da primavera e escrever um artigo de continuação. Se você não possui uma conta habr, posso publicar um artigo da minha conta ou ajudá-lo a receber um convite.Distribuição de tópicos:Spring Container - [nome de usuário]Spring AOP - [nome de usuário]Spring Web - [nome de usuário]Spring Cloud - [nome de usuário]