Usando o Java Config da Spring, preciso adquirir / instanciar um bean com escopo de protótipo com argumentos de construtor que só podem ser obtidos em tempo de execução. Considere o seguinte exemplo de código (simplificado por questões de brevidade):
@Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
onde a classe Thing é definida da seguinte maneira:
public class Thing {
private final String name;
@Autowired
private SomeComponent someComponent;
@Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
O aviso name
é final
: ele só pode ser fornecido por meio de um construtor e garante imutabilidade. As outras dependências são dependências específicas da implementação da Thing
classe e não devem ser conhecidas (fortemente acopladas) à implementação do manipulador de solicitações.
Este código funciona perfeitamente bem com a configuração XML da Spring, por exemplo:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
Como faço para conseguir a mesma coisa com a configuração Java? O seguinte não funciona com o Spring 3.x:
@Bean
@Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
Agora, eu poderia criar uma fábrica, por exemplo:
public interface ThingFactory {
public Thing createThing(String name);
}
Mas isso anula todo o sentido de usar o Spring para substituir o padrão de design ServiceLocator e Factory , o que seria ideal para esse caso de uso.
Se o Spring Java Config pudesse fazer isso, eu seria capaz de evitar:
- definindo uma interface de fábrica
- definindo uma implementação de fábrica
- escrevendo testes para a implementação da fábrica
Isso é muito trabalho (relativamente falando) para algo tão trivial que o Spring já suporta via configuração XML.
Thing
implementação é realmente mais complexa e tem dependências de outros beans (eu os omiti por brevidade). Como tal, não quero que a implementação do manipulador de solicitações saiba sobre eles, pois isso acopla fortemente o manipulador às APIs / beans de que não precisa. Vou atualizar a pergunta para refletir sua (excelente) pergunta.
@Qualifier
parâmetros em um setter @Autowired
no próprio setter.
@Bean
obras. O @Bean
método é chamado com os argumentos apropriados aos quais você passou getBean(..)
.