What is the purpose of the Spring Bean annotation name attribute? - java

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.

#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;
}

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.

Related

Spring Cache not working for abstract classes

I'm trying to use Spring Cache within abstract classes but it won't work, because, from what I can see, Spring is searching for CacheNames on the abstract class. I'm having a REST API which uses a service layer and a dao layer. The idea is to have a different cache name for every subclass.
My abstract service class looks like this:
#Service
#Transactional
public abstract class AbstractService<E> {
...
#Cacheable
public List<E> findAll() {
return getDao().findAll();
}
}
An extension of the abstract class would look like this:
#Service
#CacheConfig(cacheNames = "textdocuments")
public class TextdocumentsService extends AbstractService<Textdocuments> {
...
}
So when I start the application with this code, Spring gives me the following exception:
Caused by: java.lang.IllegalStateException: No cache names could be detected on 'public java.util.List foo.bar.AbstractService.findAll()'. Make sure to set the value parameter on the annotation or declare a #CacheConfig at the class-level with the default cache name(s) to use.
at org.springframework.cache.annotation.SpringCacheAnnotationParser.validateCacheOperation(SpringCacheAnnotationParser.java:240) ~[spring-context-4.1.6.RELEASE.jar:?]
I think this happens because Spring is searching for the CacheName on the abstract class, despite it is being declared on the subclass.
Trying to use
#Service
#Transactional
#CacheConfig
public abstract class AbstractService<E> {
}
leads to the same exception; using
#Service
#Transactional
#CacheConfig(cacheNames = "abstractservice")
public abstract class AbstractService<E> {
}
gives no exception, but then Spring Cache uses the same cache name for every subclass and ignores the cache name defined on the subclass. Any Ideas to so solve this?
This problem has been addressed in another question and is less about abstract classes and more about the framework's ability to figure out which cache to use.
Long story short (quoting from Spring documentation) you are missing appropriate CacheResolver that will work with your abstract class hierarchy:
Since Spring 4.1, the value attribute of the cache annotations are no longer mandatory, since this particular information can be provided by the CacheResolver regardless of the content of the annotation.
Therefore, your abstract class should define a caching resolver instead of directly stating the cache name.
abstract class Repository<T> {
// .. some methods omitted for brevity
#Cacheable(cacheResolver = CachingConfiguration.CACHE_RESOLVER_NAME)
public List<T> findAll() {
return getDao().findAll();
}
}
The resolver determines the Cache instance(s) to use for an intercepted method invocation. A very naive implementation can take the target repository bean (by name) and use it as the cache name
class RuntimeCacheResolver
extends SimpleCacheResolver {
protected RuntimeCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
return Arrays.asList(context.getTarget().getClass().getSimpleName());
}
}
Such resolver needs an explicit configuration:
#Configuration
#EnableCaching
class CachingConfiguration extends CachingConfigurerSupport {
final static String CACHE_RESOLVER_NAME = "simpleCacheResolver";
#Bean
#Override
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
#Bean(CACHE_RESOLVER_NAME)
public CacheResolver cacheResolver(CacheManager cacheManager) {
return new RuntimeCacheResolver(cacheManager);
}
}
I've create a Gist which describes the whole concept in more details.
Disclaimer
The above snippets are just for demonstration and are intended to give direction than to provide a complete solution. The above cache resolver implementation is very naive and doesn't consider many things (like method parameters etc.). I'd never use it in a production environment.
The way Spring handles caching is through proxies, where the #Cacheable annotation declares the cache, together with naming information processed on runtime. The cache is resolved through runtime information provided to cache resolver (no surprise it resembles some similarities to InvocationContext of classical AOP).
public interface CacheOperationInvocationContext<O extends BasicOperation> {
O getOperation();
Object getTarget();
Method getMethod();
Object[] getArgs();
}
Through the getTarget() method it is possible to figure out which bean is proxied, but in real-life, more information should be taken into account, to provide a reliable cache (like method parameters, etc).

Dependency injection of Generic subtype with Spring

I am trying to inject specific Generic bean to Generic subtype, but Spring is unable to resolve dependency. By removing type from the bean, everything works as expected. Here is an example:
public class AbstractFrom{
// ...
}
public class EmployyForm extends AbstractFrom{
// ...
}
public class CompanyForm extends AbstractFrom{
// ...
}
abstract class AbstractBean<T extends AbstractFrom>{
public abstract void calculate(T form);
}
#Component
public CompanyBean extends AbstractBean<CompanyForm>{
public void calculate(CompanyForm form){
// specific impl
}
}
#Component
public EmployeeBean extends AbstractBean<EmployyForm>{
public void calculate(EmployyForm form){
// specific impl
}
}
Here is a target class:
#Service
public BaseService{
#Autowire
public AbstractBean<AbstractFrom> baseBean; // <- NoSuchBeanDefinitionException
// #Autowire
// public AbstractBean baseBean; <- Injection works as is expected
}
Depends of active profile is initialized only CompanyBean or EmployeeBean, never both. I've also tried set the same name given beans and us #Qualifier annotation.
Does exist any way how inject this bean using diamond syntax? Does Spring is able to resolve given dependency? Using Spring 4.2.x.
Edit:
With Spring 4.3 is should be possible. See Juergen Hoeller's talk
I know you are probably not going to like this, but why not separate out the EmployeeForm and the CompanyForm to 2 separate base forms, and then in the BaseService make TWO entires, for the Autowire.
This is not a Spring answer per se, but that is what I would do, as a quick work around to see if it would work.
Separating them is not a terrible design compromise.

Spring Inheritance - Annotation

I came across this link which explains how a bean can be inherited. Assuming that HelloWorld class in this example is exposed as a bean using #Component annotation , how can create another bean which inherits this bean? Can I use extends to inherit HelloWorld bean and add #Component to the new class in order to extend the existing bean expose it as a new bean with additional features?
First you make your abstract configuration, which is achieved by not marking it as #Configuration, like this:
// notice there is no annotation here
public class ParentConfig {
#Bean
public ParentBean parentBean() {
return new ParentBean();
}
}
An then you extend it, like this:
#Configuration
public class ChildConfig extends ParentConfig {
#Bean
public ChildBean childBean() {
return new ChildBean();
}
}
The result will be exactly the same as if you did this:
#Configuration
public class FullConfig {
#Bean
public ParentBean parentBean() {
return new ParentBean();
}
#Bean
public ChildBean childBean() {
return new ChildBean();
}
}
Edit: answer to the follow-up question in the comment.
If Spring picks up both classes, parent and child, there will be problems with duplicated beans, so you cannot extend it directly. Even if you override methods, the beans from the super-class will also be instantiated by the ParentConfig.
Since your parent class is already compiled, you have 2 options:
Talk to the author of the parent class and kindly ask him to change it.
Change the #ComponentScan packages.
To clarify on solution 2:
If the parent class is in the package com.parent.ParentConfig and the child class is the package com.child.ChildConfig, you can configure the component scanning so that only classes under com.child get picked up.
You can specify the component scanning packages using the #ComponentScan("com.child") annotation on your main configuration file (think application class).

Spring Autowire Annotation with Several Interface Implementations

Suppose you have one interface
public interface A {
public void doSomething();
}
and two implementation classes
#Component(value="aImpl1")
public class AImpl1 implements A {
}
#Component(value="aImpl2")
public class AImpl2 implements A{
}
And finally a class that will use an "A" implementation:
#Component
public class MyClass {
#Autowire
A a;
}
Now if I want to inject AImpl1 I add the #Qualifier("aImpl1") while if I want to inject AImpl2 I add #Qualifier("aImpl2")
The question is: Is it possible to instruct spring somehow to look up all implementations of "A" in this case AImpl1 and AImpl2 and use some application specific conventions to choose the most appropriate implementation? for example in this case my convention could be use the implementation with the greatest suffix (i.e. AImpl2)?
EDIT: the class MyClass should not be aware at all about the implementation lookup logic, it should just find its property "a" set with an object of AImpl2.
You can inject all implentations as List:
#Autowired
List<A> as;
or as Map with bean name as key:
#Autowired
Map<String, A> as;
and then choose proper implementation manually (perhaps, in a setter method):
#Autowired
public void setAs(Map<String, A> as) {
this.a = ...;
}
Assuming you already have hundreds of interfaces and implementations (as you said in a comment), and you do not want to refactor all the code... then is a tricky problem... and this is a tricky solution:
You could create a custom BeanDefinitionRegistryPostProcessor and implement either the method postProcessBeanDefinitionRegistry or postProcessBeanFactory.
This way you have access to all bean definitions before they are instantiated and injected. Do your logic to find which is the preferred implementation for each one of your interfaces, and then, set that one as primary.
#Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
// this method can be used to set a primary bean, although
// beans defined in a #Configuration class will not be avalable here.
}
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
// here, all beans are available including those defined by #configuration, #component, xml, etc.
// do some magic to somehow find which is the preferred bean name for each interface
// you have access to all bean-definition names with: beanFactory.getBeanDefinitionNames()
String beanName = "aImpl2"; // let's say is this one
// get the definition for that bean and set it as primary
beanFactory.getBeanDefinition(beanName).setPrimary(true)
}
}
The hard part is to find the bean name, it depends of the specifics of your application. I guess that having a consistent naming convention will help.
Update:
It seems that both methods in the interface BeanDefinitionRegistryPostProcessor can be used for this purpose. Having in mind that in the postProcessBeanDefinitionRegistry phase, beans configured through #configuration classes are not yet available, as noted in the comments below.
On the other hand they are indeed available in postProcessBeanFactory.
If you have a Configuration class you could use a method in that to make the decision of which implementation of A to return. Then the autowired will inject the appropriate instance for that class.
#Configuration
public class ApplicationConfiguration {
#Bean
A getA() {
// instantiate the implementation of A that you would like to have injected
// or you could use reflection to find the correct class from the classpath.
// return the instance
}
}
This assumes you always want to use the same instance everywhere you are injecting A. If not, then you could have different #Bean annotated methods with names to get different versions.
You can try to use Spring Profiles.

Java Spring Problem with annotations

I've a problem with spring. I'm replacing the xml file based configuration of spring with annotation based configuration. Because of that I runned into the following problem. Theres is a class, where one field is configured by class based autowiring. Since yet, there has been only one candidate. But now there is more then one candidate, because I've added the #Named tag to mutliple classes of the same interface.
Here is a code example:
The class with the autowiring field:
public class AutowiringClass<X, Y> {
// This is the field which is autowired
private Autowired<X, Y> bean;
.....
}
Then there is a second class, which extends AutoWiringClass with specific generic arguments:
public class TestClass extends AutoWiringClass<ObjectX, ObjectY> {
.....
}
The Problem is, that spring doesn't know which class it should use, since there are more than once class of the type Autowiring but with different generic types (ObjectX, ObjectY). I thought, that the different generic types will do the thing.. but they doesn't :(
It would be awesome if anybody has an solution for that.
Qualifiers are what you are looking for. When you register a class as a Spring bean (using #Component or the like) you can pass a name as an argument. Then when you are autowiring a property, add a #Qualifier annotation with that bean's name. So:
#Component("Test1")
public class Test { }
#Component("Test2")
public class BetterTest extends Test {}
public class TestUser {
#Autowired
#Qualifier("Test1")
private Test test;
}
Generics won't help you due to type erasure, Spring can't do nothing about it. But you can either use #Primary annotation to denote the default implementation that should be always used or switch to autowiring by name rather than by type. Then Spring will use field name when in doubt.

Categories

Resources