Anotação @ Lookup na primavera
1. Introdução
Neste tutorial rápido, vamos dar uma olhada no suporte de injeção de dependência de nível de método do Spring, por meio da anotação@Lookup.
2. Por que@Lookup?
Um método anotado com@Lookup diz ao Spring para retornar uma instância do tipo de retorno do método quando o invocarmos.
Essencialmente, Spring irá sobrescrever nosso método anotado e usar o tipo de retorno e parâmetros de nosso método como argumentos paraBeanFactory#getBean.
@Lookup é útil para:
-
Injetando um bean com escopo de protótipo em um bean singleton (semelhante aProvider)
-
Injetando dependências processualmente
Observe também que@Lookup é o equivalente Java do elemento XMLlookup-method.
3. Usando@Lookup
3.1. Injetando bean com escopo de protótipo em um bean singleton
Se decidirmos ter um protótipo de bean Spring, somos quase imediatamente confrontados com o problema de como nossos Spring beans singleton acessarão esses protótipos Spring beans?
Agora,Provider é certamente uma maneira, embora@Lookup seja mais versátil em alguns aspectos.
Primeiro, vamos criar um bean de protótipo que posteriormente injetaremos em um bean singleton:
@Component
@Scope("prototype")
public class SchoolNotification {
// ... prototype-scoped state
}
E se criarmos um singleton bean que usa@Lookup:
@Component
public class StudentServices {
// ... member variables, etc.
@Lookup
public SchoolNotification getNotification() {
return null;
}
// ... getters and setters
}
Usando@Lookup, podemos obter uma instância deSchoolNotification por meio de nosso singleton bean:
@Test
public void whenLookupMethodCalled_thenNewInstanceReturned() {
// ... initialize context
StudentServices first = this.context.getBean(StudentServices.class);
StudentServices second = this.context.getBean(StudentServices.class);
assertEquals(first, second);
assertNotEquals(first.getNotification(), second.getNotification());
}
Observe que emStudentServices, deixamos o métodogetNotification como um esboço.
Isso ocorre porque o Spring sobrescreve o método com uma chamada parabeanFactory.getBean(StudentNotification.class), então podemos deixá-lo vazio.
3.2. Injetando dependências de maneira processual
Ainda mais poderoso, porém, é que@Lookup nos permite injetar uma dependência proceduralmente, algo que não podemos fazer comProvider.
Vamos aprimorarStudentNotification com algum estado:
@Component
@Scope("prototype")
public class SchoolNotification {
@Autowired Grader grader;
private String name;
private Collection marks;
public SchoolNotification(String name) {
// ... set fields
}
// ... getters and setters
public String addMark(Integer mark) {
this.marks.add(mark);
return this.grader.grade(this.marks);
}
}
Agora, depende de algum contexto do Spring e também de um contexto adicional que forneceremos processualmente.
Podemos então adicionar um método aStudentServices que obtém os dados do aluno e os persiste:
public abstract class StudentServices {
private Map notes = new HashMap<>();
@Lookup
protected abstract SchoolNotification getNotification(String name);
public String appendMark(String name, Integer mark) {
SchoolNotification notification
= notes.computeIfAbsent(name, exists -> getNotification(name)));
return notification.addMark(mark);
}
}
Em tempo de execução, o Spring implementará o método da mesma maneira, com alguns truques adicionais.
Primeiro, observe que ele pode chamar um construtor complexo, bem como injetar outros beans Spring, permitindo-nos tratarSchoolNotification um pouco mais como um método ciente do Spring.
Ele faz isso implementandogetSchoolNotification com uma chamada parabeanFactory.getBean(SchoolNotification.class, name).
Em segundo lugar, às vezes podemos fazer o método@Lookup-annotated abstrato, como no exemplo acima.
Usarabstract é um pouco mais bonito do que um esboço, mas só podemos usá-lo quandodon’tcomponent-scan or @Bean-manage o bean circundante:
@Test
public void whenAbstractGetterMethodInjects_thenNewInstanceReturned() {
// ... initialize context
StudentServices services = context.getBean(StudentServices.class);
assertEquals("PASS", services.appendMark("Alex", 89));
assertEquals("FAIL", services.appendMark("Bethany", 78));
assertEquals("PASS", services.appendMark("Claire", 96));
}
Com esta configuração, podemos adicionar dependências Spring, bem como dependências de método aSchoolNotification.
4. Limitações
Apesar da versatilidade de@Lookup, existem algumas limitações notáveis:
-
Métodos anotados em@Lookup, comogetNotification,, devem ser concretos quando a classe circundante, comoStudent,, é analisada por componente. Isso ocorre porque a varredura de componentes ignora os beans abstratos.
-
Métodos@Lookup-annotados não funcionarão quando a classe ao redor for gerenciada por@Bean.
Nessas circunstâncias, se precisarmos injetar um bean de protótipo em um singleton, podemos considerarProvider uma alternativa.
5. Conclusão
Neste artigo rápido, aprendemos como e quando usar a anotação@Lookup do Spring, incluindo como usá-la para injetar beans com escopo de protótipo em beans singleton e como usá-la para injetar dependências proceduralmente.
Todo o código usado para este tutorial pode ser encontradoover on Github.