6

It is possible to @Autowired bean with class and @Qualifier in Spring.

How to do the same thing programmatically? I.e. search context for bean giving it's class and it's qualifier?

I see a plenty of getBean() methods, neither of them explicitly claims it can do the thing.

Dims
  • 47,675
  • 117
  • 331
  • 600
  • 1
    Not easily, why would you need to access it programmatically... Generally when needing to do manual lookups you are doing things in a wrong way already. – M. Deinum Jun 21 '16 at 11:53
  • I want to modularize my contexts. I don't believe all beans should be lumped together into one big heap. So, I am experimenting with parent contexts. `AnnotationConfigApplicationContext` doesn't have ability to set parent on construct (which of course also mean I am doing wrong way), so I am constructing child context inside a bean within parent context and then wish to grab some beans from child context to use them. I can't autowire to keep separation. – Dims Jun 21 '16 at 12:14
  • Ehr... What do you think the `setParent` method is for? But then still why do you need to get the beans programmatically... The fact you use a single context or 100 contexts doesn't change the fact that you auto wire beans. Also what do you gain with this setup, apart from additional complexity? From a functionality pov you don't gain anything, it might even slow things down and also be aware that applying AOP has to be done in each context . – M. Deinum Jun 21 '16 at 12:26
  • Sure, I am using `setParent()`. I would like to lower complexity not to increase it. The difference is simple: if I have one context with million beans it is harder to understand them, than if I had 1000 contexts with 1000 beans each. This is splitting big complex task into smaller and simpler subtasks. I am surprised you didn't heard about this thing ;) – Dims Jun 21 '16 at 12:30
  • IMHO you are actually complicating things because now you have 1000 places instead of 1 place to look, with the increased complexity of adding AOP to all of those contexts (else transactions, logging etc. won't work). If you have a hard time understanding things the main issue lies in your application architecture not in the fact you have 1 or 1000 application contexts. – M. Deinum Jun 21 '16 at 12:34
  • I don't believe that something is incorrect if it is unknown what is correct. You say that if I have the following connectivity between my beans https://i.imgur.com/TMI4DWO.jpg I shouldn't put them into separate contexts? Okay I heard you but can't regard this reasonable. – Dims Jun 21 '16 at 12:42
  • No I don't see that necessity. If a service calls another service why should all those things be in separate contexts... Which make things even harder to debug. If those things should be separated, they should be separate applications (microservices perhaps) which call each other. That way you really have a clear boundary and not a virtual boundary which introduces only complexity. They should maybe be in separate configurations but not separate contexts. Your context is basically your application (the root context) and the integration parts (`DispatcherServlet` / `MessageDispatcherServlet`). – M. Deinum Jun 21 '16 at 12:46
  • Sorry, can't infer how this can be applicable to non-web application. – Dims Jun 21 '16 at 12:52
  • That is still again a single application, not 10 applications. You still have a single application, maybe a front end which you want to separate (see that as the one from the `DispatcherServlet`). – M. Deinum Jun 21 '16 at 12:56
  • You said "it should be separate applications, may be microservices". So, imagine I have single application, consisting of many microservices, but these thing doesn't supported by any application server. – Dims Jun 21 '16 at 13:18
  • Then you don't have microservices or separate applications but a single application. I guess we have to agree to disagree... I don't see the added value in what you are trying to do, using a correct packaging structure and separate configuration classes should be enough. There is no need to make the bootstrapping and usage more complex by adding a context per package (assuming you package by functionality and not technical layer). – M. Deinum Jun 21 '16 at 13:20

3 Answers3

13

You can use BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier):

/**
     * Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
     * qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
     * qualifier, or having a bean name matching the given qualifier.
     * @param beanFactory the BeanFactory to get the target bean from
     * @param beanType the type of bean to retrieve
     * @param qualifier the qualifier for selecting between multiple bean matches
     * @return the matching bean of type {@code T} (never {@code null})
     * @throws NoUniqueBeanDefinitionException if multiple matching beans of type {@code T} found
     * @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
     * @throws BeansException if the bean could not be created
     * @see BeanFactory#getBean(Class)
     */
    public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier)
            throws BeansException;

I think that it's exactly what you need.

  • 4
    The `BeanFactory` can be found from `applicationContext.getAutowireCapableBeanFactory()` – neXus May 22 '19 at 09:48
  • I init the spring application in flink's DataSource/Sink class like this ```java application = new SpringApplication(FlinkDemoJob.class); context = application.run(); qServiceClient = BeanFactoryAnnotationUtils.qualifiedBeanOfType(context.getAutowireCapableBeanFactory(), QServiceClient.class, "abcde"); ``` but got no luck, it always return the first(I am not sure, but it's not what I want) bean – UnixAgain May 18 '20 at 11:40
2

Try this one -

applicationContext.getBeansOfType(MyType.class).get("bean-name")
shachar
  • 641
  • 5
  • 12
  • 3
    Qualifier is not always equal to bean name. It can be set explicitly to some different string. – Dims Jun 21 '16 at 12:17
0

If you want Spring to handle @Autowired fields/properties programmatically, you need to get the AutowireCapableBeanFactory instance from your ApplicationContext and call factory.autowireBean(myClassInstanceWithBeansToAutowire);.

neomega
  • 712
  • 5
  • 19