1
First of all, let's talk about DI.
Note from Spring Doc,
Dependency management and dependency injection are different things.
- Dependency management is "assemble all the libraries needed (jar files) and get them onto your classpath at runtime, and possibly at compile time".
- Dependency injection is, suppose you want a
Service
object in your class, instead of create it using service = new Service();
, you let the spring framework handle the life cycle of that bean.
Example of Dependency management:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
</dependencies>
So that you have all these jar files in your project.
spring-context-4.2.5.RELEASE.jar
spring-aop-4.2.5.RELEASE.jar
spring-beans-4.2.5.RELEASE.jar
spring-core-4.2.5.RELEASE.jar
Example of Dependency Injection:
In your quick-start example, you inject MessageService
into MessagePrinter
by using constructor injection. You didn't create a MessageService
anywhere. Spring container creates it for you.
@Component
public class MessagePrinter {
final private MessageService service;
@Autowired
public MessagePrinter(MessageService service) {
this.service = service;
}
public void printMessage() {
System.out.println(this.service.getMessage());
}
}
@Configuration
@ComponentScan
public class Application {
@Bean
MessageService mockMessageService() {
return new MessageService() {
public String getMessage() {
return "Hello World!";
}
};
}
...
}
2
Now let's talk about transitive dependency and run-time dependency.
Transitive dependency
It means to discover the libraries that your own dependencies require and including them automatically.
For example, if you specified dependencies A and B in pom.xml
. And A depends on C, D. B depends on E. You don't need to include C, D, E in your configuration.
Because of transitive dependency, C, D, E will be included automatically.
Runtime dependency
It is one type of dependency scopes to limit the transitive dependency.
"This scope indicates that the dependency is not required for
compilation, but is for execution. It is in the runtime and test
classpaths, but not the compile classpath."
3
Now the question is: is there any case that for DI "you don’t need to compile against Spring APIs", instead you can set the scope as runtime? Similar question here.
Yes, one example I can think of is web application. Suppose I'm using Strtuts with Spring plugin. (below example comes from "Struts 2 in Action" from Manning)
I want to tell Spring to create an instance of the Login
class to use as its action object for the request.
add a spring web context listener to web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
define a bean Login
named as springManagedLoginAction
in
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="portfolioService" class="manning.chapterNine.utils.PortfolioServiceJPAImpl"/>
<bean id="springManagedLoginAction" class="manning.chapterNine.Login" scope="prototype">
<property name="portfolioService" ref="portfolioService"/>
</bean>
</beans>
use this bean in the action class in struts-config-login.xml
<action name="Login" class="springManagedLoginAction">
<result type="redirectAction">
<param name="actionName">AdminPortfolio</param>
<param name="namespace">/chapterEight/secure</param>
</result>
<result name="input">/chapterEight/Login.jsp</result>
</action>