简体   繁体   中英

Dependency injection, Scala and Spring

I love the concept of DI and loosely coupled system, a lot. However, I found tooling in Spring lacking at best. For example, it's hard to do "refactoring", eg to change a name of a bean declared in Spring. I'm new to Spring, so I would be missing something. There is no compiling time check etc.

My question is why do we want to use XML to store the configuration? IMO, the whole idea of Spring (IoC part) is to force certain creational pattern. In the world of gang-of-four patterns, design patterns are informative. Spring (and other DIs) on the other hand, provides very prescribed way how an application should be hooked up with individual components.

I have put Scala in the title as well as I'm learning it. How do you guys think to create a domain language (something like the actor library) for dependency ingestion. Writing the actual injection code in Scala itself, you get all the goodies and tooling that comes with it. Although application developers might as well bypass your framework, I would think it's relatively easy to standard, such as the main web site/app will only load components of certain pattern.

There's a good article on using Scala together with Spring and Hibernate here .

About your question: you actually can use annotations. It has some advantages. XML, in turn, is good beacause you don't need to recompile files, that contain your injection configs.

There is an ongoing debate if Scala needs DI. There are several ways to "do it yourself", but often this easy setup is sufficient:

//the class that needs injection
abstract class Foo {
  val injectMe:String
  def hello = println("Hello " + injectMe)
}

//The "binding module"
trait Binder {
  def createFooInstance:Foo
}

object BinderImpl extends Binder {
  trait FooInjector {
    val injectMe = "DI!"   
  }

  def createFooInstance:Foo = new Foo with FooInjector
}

//The client
val binder:Binder = getSomehowTheRightBinderImpl  //one way would be a ServiceLoader
val foo = binder.createFooInstance
foo.hello
//--> Hello DI!

For other versions, look here for example.

There are different approaches to DI in java, and not all of them are necessarily based on xml.

Spring

Spring provides a complete container implementation and integration with many services (transactions, jndi, persistence, datasources, mvc, scheduling,...) and can actually be better defined using java annotations.

Its popularity stems from the number of services that the platform integrates, other than DI (many people use it as an alternative to Java EE , which is actually following spring path starting from its 5 edition).

XML was the original choice for spring , because it was the de-facto java configuration standard when the framework came to be. Annotations is the popular choice right now.

As a personal aside, conceptually I'm not a huge fan of annotation-based DI , for me it creates a tight coupling of configuration and code, thus defeating the underlying original purpose of DI .

There are other DI implementation around that support alternative configuration declaration: AFAIK Google Guice is one of those allowing for programmatic configuration as well.


DI and Scala

There are alternative solutions for DI in scala, in addition to using the known java frameworks (which as far as I know integrate fairly well).

For me the most interesting that maintain a familiar approach to java is subcut .

It strikes a nice balance between google guice and one of the most well-known DI patterns allowed by the specific design of the scala language: the Cake Pattern . You can find many blog posts and videos about this pattern with a google search .

Another solution available in scala is using the Reader Monad , which is already an established pattern for dynamic configuration in Haskell and is explained fairly well in this video from NE Scala Symposium 2012 and in this video and related slides .

The latter choice goes with the warning that it involves a decent level of familiarity with the concept of Monads in general and in scala, and often aroused some debate around its conceptual complexity and practical usefulness. This related thread on the scala-debate ML can be quite useful to have a better grip on the subject.

I love the concept of DI and loosely coupled system, a lot. However, I found tooling in Spring lacking at best. For example, it's hard to do "refactoring", eg to change a name of a bean declared in Spring. I'm new to Spring, so I would be missing something. There is no compiling time check etc.

You need a smarter IDE. IntelliJ from JetBrains allows refactoring, renaming, etc. with full knowledge of your Spring configuration and your classes.

My question is why do we want to use XML to store the configuration?

Why not? You have to put it somewhere. Now you have a choice: XML or annotations.

IMO, the whole idea of Spring (IoC part) is to force certain creational pattern. In the world of gang-of-four patterns, design patterns are informative.

ApplicationContext is nothing more than a big object factory/builder. That's a GoF pattern.

Spring (and other DIs) on the other hand, provides very prescribed way how an application should be hooked up with individual components.

GoF is even more prescriptive: You have to build it into objects or externalize it into configuration. Spring externalizes it.

I have put Scala in the title as well as I'm learning it. How do you guys think to create a domain language (something like the actor library) for dependency ingestion.

You must mean "injection".

Writing the actual injection code in Scala itself, you get all the goodies and tooling that comes with it.

Don't see what that will buy me over and above what Spring gives me now.

Although application developers might as well bypass your framework, I would think it's relatively easy to standard, such as the main web site/app will only load components of certain pattern.

Sorry, I'm not buying your idea. I'd rather use Spring.

But there's no reason why you shouldn't try it and see if you can become more successful than Spring. Let us know how you do.

I cannot agree that XML is problem in Java and Spring: I use Spring and Java extensively without to much XML because most configuration is done with annotations (type and name is powerful contract) - it looks really nice. Only for 10% cases I use XML because it is easier to do it in XML than code special solution with factories / new classes / annotations. This approach was inspired by Guice and Spring from 3.0 implements its as JSR-330 (but even that I use Spring 2.5 with spring factory configured with JSR-330 annotations instead of default spring-specific @Autowired).

Probably scala can provide better syntax for developing in DI style and I'm looking at it now (pointed Cake Pattern).

i can't really comment on scala, but DI helps enforce loose coupling. It makes refactoring large apps soooo much easier. If you don't like a component, just swap it out. Need another implementation for a particular environment, easy just plug in a new component.

I agree! To me he way most people use Spring is a mild version of hell.

When you look at the standard Springified code there are interfaces everywhere, and you never really know what class is used to implement an interface. You have to look into some fantastic configuration to find that out. Easy read = not. To make this code surfable you need a very advanced IDE, like Intelly J.

How did we end up in this mess? I blame automated unit testing! If you want to connect mocks to each and every class you can not have dependencies. If it wasn't for unit testing we could probable do just as well without loose coupling, since we do not want the customer to replace single classes willy nilly in our Jars.

In Scala you can use patterns, like the "Cake Patten" to implement DI without a framework. You can also use structural typing to do this. The result is still messy compared to the original code.

Personally I think one should consider doing automated testing on modules instead of classes to escape this mess, and use DI to decouple entire modules. This strategy is by definition not unit testing. I think most of the logic lies in the actual connections between classes, so IMHO one will benefit more from module testing than unit testing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM