0

I'm just learning spring, and something struck me as very odd about the annotation configurations using the name attribute as a string.

@Bean(name = "com.my.injected.Service")
public InjectedService injectedService() {
    return injectedService;
}

Is this name similar to the Spring Bean XML configuration id and class attributes?

<bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
</bean>

Why isn't this simply

@Bean(clazz = com.my.injected.Service.class)
public InjectedService injectedService() {
    return injectedService;
}

instead?

You're fully qualifying the path in both cases and actually using the class makes it way easier for your IDE to tell you when you've screwed it up. I understand that the XML configuration came first, and naturally it was always looking up things by string, so is this just a holdover? Is there some advantage to using strings or major disadvantage to using .class?

Question was originally based on a false premise. I edited it to spell out what this premise was and make it less confusing for new people who come along. Hopefully I did this such that the given answers are still exactly applicable; apologies if not.

Patrick M
  • 10,547
  • 9
  • 68
  • 101
  • Because it defeats the purpose of *naming* something. You chose to provide a FQN. `name="DasBean"` is just as good. Do you know what that annotation is meant for? – kolossus May 07 '15 at 17:21
  • Haha, clearly I don't. I think I must just be following an example that is abusing the annotation. – Patrick M May 07 '15 at 17:25

2 Answers2

2

@Bean annotation is meant to provide a spring bean. The type of the bean to provide will be the same type of the class/interface you define in the return method. So, instead of declaring to return a concrete class in the method, return the top (abstract) class/interface instead.

Imagine this case:

public interface MyEntityDao {
    MyEntity get(String id);
}

@Repository
public class MyEntityDaoDatabaseImpl implements MyEntityDao {
    @Override
    public MyEntity get(String id) {
        /* implementation that goes to database every time */
    }
}

@Repository
public class MyEntityDaoCacheImpl implements MyEntityDao {
    @Override
    public MyEntity get(String id) {
        /* implementation that looks the data
           up in cache, never in database */
    }
}

@Configuration
public class MyAppConfiguration {
    @Bean
    public MyEntityDaoDatabaseImpl method1() {
        return new MyEntityDaoDatabaseImpl();
    }
    @Bean
    public MyEntityDaoCacheImpl method2() {
        return new MyEntityDaoCacheImpl();
    }
}

@Service
public class MyEntityService {
    @Autowired //what to inject here?
    MyEntityDao dao;
}

In case above, there are two implementations of the proposed interface. How the framework may be able to understand which implementation to use except for the name?

@Service
public class MyEntityService {
    @Autowired
    @Qualifier("properBeanNameToInject")
    MyEntityDao dao;
}
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • Does the name really give you the power to control the interface vs. implementation type though? The page you linked says `@Bean(name={"b1","b2"}) // bean available as 'b1' and 'b2', but not 'myBean'`, which strongly implies the name is just providing syntatic sugar for however you want to refer to the injected object as in *other* classes. – Patrick M May 07 '15 at 17:29
  • @PatrickM added a case where the name becomes more relevant than the top class/interface. – Luiggi Mendoza May 07 '15 at 17:38
1

Bean name is not necessarily related to its class or even any of interfaces it implements. It is a name and nothing more. When you use the annotation configuration, Spring figures out what the exact class or interface the @Bean provides like the rest of java code would: either through the fully qualified name in the code or through the imports specified in the file. In your case, you presumably have an import com.my.injected.Service; statement at the top of the java file.

Your example is using the fully qualified class name as the bean name. It is your choice. You could use any other identifier. Using the fully qualified name could be useful if your code is providing an object that is named exactly like another 3rd party @Bean object that your code must include or consume. However, you could just as easily use name = "myService".

The bean name helps Spring (and application programmer) to distinguish between multiple instances of of the same bean class because you can deploy the same class as bean several times. If only one instance of bean type appear you event do not have to give it name manually: spring does this by default.

If you have several beans that have the same type or implement the same interface and you want to refer specific bean use @Qualifier annotation.

Patrick M
  • 10,547
  • 9
  • 68
  • 101
AlexR
  • 114,158
  • 16
  • 130
  • 208
  • Ah, so the only reason to provide the fully qualified name as the `name` attribute is if you need to override the default name, which I now gather is the name of the method or object you slap the `@Bean` onto. So if I had `com.my.injected.Service` and `com.thirdparty.injected.Service` in the same project, I could use this fully qualified name scheme to disambiguate the two. – Patrick M May 07 '15 at 17:35
  • Yes, you can. IMHO such long name is not needed, but you can use it if you want. I prefer shorter names. For example your have 2 beans that implement `InjectionServece`: `methodInjector` and `constructionInjector` (I do not know whether these names make sense for you, this is only for example). In this case I'd call one of them `methodInjector`, other `constructorInjector`. – AlexR May 07 '15 at 17:39