How to select a service implementation in a Grails application? - spring

I have several services implementing a common interface and I want to be able to choose one of them to inject into other services when my application starts up.
I have tried referencing the service implementation from resources.groovy as shown below but then Spring makes a new instance of the selected service and doesn't autowire its dependencies.
How can I get this solution to work? Or is there another way?
class MyService {
Repository repository
interface Repository {
void save(...)
}
}
class MySqlRepositoryService implements MyService.Repository { ... }
class FileRepositoryService implements MyService.Repository { ... }
resources.groovy:
beans = {
...
repository(FileRepositoryService) { }
}

It's of course possible to retrieve the reference to service from hand-built factory, but in my opinion, the approach you've taken is the best one. I use it myself, because it gathers all the information on configuration phase of the application in one place, so it's easier to track down which implementation is used.
The pitfall with autowiring that you've encountered can be explained very easily. All the classes put in grails-app/services are automatically configured by Grails as Spring singleton beans with autowiring by name. So the bean definition you've placed in grails-app/conf/resources.groovy creates another bean, but without the defaults imposed by Grails conventions.
The most straightforward solution is to put the implementation in src/groovy to avoid duplication of beans and use the following syntax to turn on the autowiring:
beans = {
repository(FileRepositoryService) { bean ->
bean.autowire = 'byName'
}
}

Related

Is there some way to get access to Spring bean from Spock extension?

There is an example what I want to do.
The service client is a Spring bean, which is retrieving from external configuration class and should be called from Spock extension.
class ServiceCleintExtension implements IGlobalExtension {
#Autowired
ServiceCLient client
#Override
void start() {
client.execute()
}
...
}
UPD:
I've found a solution by using Spring TestExecutionListener and custom static "container" for SpecInfo/FeatureInfo.
No that is not possible, IGlobalExtension are initialized and manged by Spock. Furthermore, they are singletons which doesn't mesh well with multiple possible Spring contexts.
If you just want to call a method on an injected bean during setup, then I'd suggest to use an annotation based extension. Look at the builtin AutoCleanup extension for reference.

Spring fallback bean implementation

I'm currently trying to configure Spring Boot (using Java Annotations and ComponentScan) for the following scenario:
Scenario
There's an interface MyService.
I want to provide a default implementation for MyService, let's call it MyDefaultService.
If the component scan detects no other implementation for MyService, Spring should instantiate MyDefaultService as a "fallback".
If there is a different implementation of MyService present, let's say MyCustomService, then that bean should always take precedence over MyDefaultService when autowiring a dependency to MyService. In that regard, MyDefaultService should be recessive (as opposed to #Primary).
Ideally, there should not need to be an additional annotation on MyCustomService to have it "override" MyDefaultService.
Ideally, no explicitly implemented factories or factory methods should be required.
Question
The question is: how do I need to annotate the MyDefaultService class in order to achieve this?
What I tried so far to solve the problem
Annotating MyDefaultService with #ConditionalOnMissingBean(MyService.class). Didn't work because MyDefaultService is never used, even if there is no other implementation of MyService.
There is an annotation called #Primarythat solves the problem. However, it needs to reside on MyCustomService, a class that I try to keep free of additional annotations. Essentially, I need the inverse annotation of #Primary on MyDefaultService. However, I couldn't find such an annotation.
Concrete use case
I am developing a service layer in one project, and a different project will implement a web UI layer on top of it. The UI project has a dependency to the service layer project. However, for certain functionalities implemented at the service layer, I need to know which user is currently logged in at the web context. So I have to define a service interface for that in the service layer project, such that it can be implemented by the UI project. However, for testing purposes in the service-layer project, I need a default implementation of that interface. Also, in case that the UI project team forgets to implement this interface, the app should not crash, but instead instantiate the fallback bean and issue a warning.
Thanks & kind regards,
Alan
I suggest writing an implementation of FactoryBean to do this. Your FactoryBean would scan the bean factory looking for beans that implement MyService, and if it finds one it returns that bean from getObject. If it doesn't, then it can instantiate MyDefaultService directly and return that. Your factory bean then gets annotated with #Primary.
So pieces like this (pseudo-code):
public class MyServiceFactory implements FactoryBean<MyService> {
ListableBeanFactory beanFactory;
public MyService getObject() {
Map beans = beanFactory.getBeansOfType(MyService.class)
if (beans.isEmpty())
return new MyDefaultService(); // plus args, obviously
else
return get_some_bean_from_the_map
}
}
and then
#Primary
#Bean
public MyServiceFactory MyServiceFactory() {
return new MyServiceFactory();
}
Spring will automatically handle the factory bean (i.e. it will make the MyService object available as a bean for injection like normal.
This solution doesn't require any special magic, and it's fairly obvious how it works. You can also handle errant cases such as multiple MyService beans being declared.

Spring Java config, #Autowire vs. Constructor Injection, #Transactional and CGLIB

We've been using #Autowired plus Java-based Spring configuration with some success but now, we're losing control. Everyone is starting to add autowired dependencies everywhere, creating cycles and strange bugs.
So we are considering using constructor injection and autowiring of Spring configurations.
Old:
class Bean {
#Autowired Foo foo;
}
#Configuration
#Import( FooCfg.class )
class BeanCfg {
#Bean public Bean bean() { return new Bean(); }
}
New:
class Bean {
public Bean(Foo foo) {...}
}
#Configuration
class BeanCfg {
#Autowired FooCfg fooCfg;
#Bean public Bean bean() { return new Bean(fooCfg.foo()); }
}
This works pretty well (and it drives people to split beans instead of creating monsters with 10+ constructor arguments).
But it fails when Bean has a method annotated with #Transactional since CGLIB then tries to create a proxy which fails since it can't find a no-argument constructor.
What's the solution for this?
You have a couple of possible of solutions
Introduce interfaces your classes
Upgrade the Spring Version to at least 4.0
Add protected no-arg constructor
Introduce Interfaces
When introducing interfaces for your classes you can drop the usage of CgLib. Spring will then be able to use JDK Dynamic Proxies which work around interfaces. It creates a proxy around an already existing bean instance and that proxy implements all the interfaces of the class it is wrapping. That way it doesn't matter if your class has a no-arg constructor or not.
Upgrade to Spring 4
In Spring 4.0 support was added to allow proxying of classes with a missing no-arg constructor (See SPR-10594). To enable this upgrade your Spring version and add Objenesis to your classpath, Spring 4 comes with its own repacked cglib version so that shouldn't be needed anymore.
One thing to note is that you should have a constructor with no logic if you do null checks or init logic in the constructor it might fail in the case where cglib creates an instance. I would suspect that it pass null to all the constructor arguments (or some default for primitives).
Added protected no-arg constructor
Cglib needs to be able to create an instance which is used to wrap the actual class. It should be enough to have a protected constructor in your classes so that cglib can call it.

Spring: how AnnotationConfigWebApplicationContext could not overwrite later beans?

I have a web application that use Sring IoC framework.
I use the Java configuration for Spring, and I only use #Configuration annoted module definition (no DI related tags elsewhere in the code).
The Spring registry is built on web application start-up thanks to (a bit modified version of) Spring context loader listener, and the contextConfigLocation param in web.xml configured to point to the #Configuration annotated class.
All that is good and I get a AnnotationConfigWebApplicationContext.
Now, I want to have plugins in my application, that will have their own #Configuration annotated configuration classes, and will use some of the main application services. BUT I don't want to have main application to be modified to load these new modules.
So, I thought that I could simply use the package searching of annotated class for that, but now, it seems that I can use two beans with the same type, even if they have different ids, and clearly AnnotationConfigWebApplicationContext doc states that:
Note: In case of multiple #Configuration classes, later #Bean definitions will override ones defined in earlier loaded files. This can be leveraged to deliberately override certain bean definitions via an extra Configuration class.
I don't want that, because modules should be able to contribute alternative version of services, not (alwways) override existing one - especcially if I want to have a "moduleDef" bean.
I tried to use differents approach on that, but the hierachy of Context and related services is just to big for me.
So, does anybody know how I could reach my goal ?
Thanks
You can have multiple beans of the same type, but You cannot have 2 or more beans with the same ID in a single Spring ApplicationContext - no matter if You use XML or JavaConfig.
The overriding mechanism matches the bean ID's, so all You need to do is to ensure unique ID, i.e.: coreModuleDef, someOtherModuleDef, anotherModuleDef. I don't think You need the ID of each module definition to be identical? What should be sufficient is the type to be the same, but not ID.
You can also turn off the overriding mechanism by setting allowBeanDefinitionOverriding to false on Your AnnotationConfigWebApplicationContext to get an exception if You accidentally override a bean:
public class MyDispatcherServlet extends DispatcherServlet {
#Override
protected void postProcessWebApplicationContext(
ConfigurableWebApplicationContext wac) {
((AnnotationConfigWebApplicationContext) wac)
.setAllowBeanDefinitionOverriding(false);
}
}
or:
public class MyContextLoaderListener extends ContextLoaderListener {
#Override
protected void customizeContext(
ServletContext servletContext,
ConfigurableWebApplicationContext applicationContext) {
((AnnotationConfigWebApplicationContext) wac)
.setAllowBeanDefinitionOverriding(false);
}
}

How to use spring to resolve dependencies of an object created manually?

I would like to know if it's possible to use Spring to resolve the dependencies of an object created manually in my program. Take a look at the following class:
public class TestClass {
private MyDependency md;
public TestClass() {
}
...
public void methodThaUsesMyDependency() {
...
md.someMethod();
...
}
}
This TestClass is not a spring bean, but needs MyDependency, that is a spring bean. Is there some way I can inject this dependency through Spring, even if I instantiate TestClass with a new operator inside my code?
Thanks
Edit: The method I'm describing in my original answer below is the general way to accomplish DI external of the container. For your specific need - testing - I agree with DJ's answer. It's much more appropriate to use Spring's test support, for example:
#Test
#ContextConfiguration(locations = { "classpath*:**/applicationContext.xml" })
public class MyTest extends AbstractTestNGSpringContextTests {
#Resource
private MyDependency md;
#Test
public void myTest() {
...
While the above example is a TestNG test, there is also Junit support explained in 8.3.7.2. Context management and caching.
General approach: Annotate your class with #Configurable and utilize AspectJ load-time or compile-time weaving. See 6.8.1 in the Spring documentation on AOP for more details.
You can then annotate your instance variables with #Resource or #Autowired. Though they accomplish the same goal of dependency injection, I recommend using #Resource since it's a Java standard rather than Spring-specific.
Lastly, remember to consider using the transient keyword (or #Transient for JPA) if you plan on serializing or persisting the objects in the future. Chances are you don't want to serialize references to your DI'd repository, service, or component beans.
See the autowire() method on the AutowireCapableBeanFactory class. If you use an ClasspathXmlApplicationContext, you can get the factory with getAutowireCapableBeanFactory()
To get the ApplicationContext, you would need to use a static singleton or other central repository, such as JNDI or a Servlet container. See DefaultLocatorFactory on how to get an instance of the ApplicationContext.
If what you need is for testing purposes, Spring has good support for the scenario that you described above.
Check out Spring Reference manual section on Testing

Resources