user2418306
user2418306

Reputation: 2382

Spring context as runtime dependency

I'm puzzled by this section of spring documentation.

For example, to create an application context and use dependency injection to configure an application, your Maven dependencies will look like this:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.5.RELEASE</version>
        <scope>runtime</scope>
    </dependency> 
</dependencies>

Note the scope can be declared as runtime if you don’t need to compile against Spring APIs, which is typically the case for basic dependency injection use cases.

I know about JSR 330 (DI annotations). But how do you decouple from ApplicationContext class? And if you do decouple from it why then still depend on spring?

How, for example, can quick start be rewritten having spring-context as a runtime dependency? Or what would be the "basic dependency injection use case"?

Upvotes: 8

Views: 4104

Answers (5)

Jakub Balhar
Jakub Balhar

Reputation: 315

I am not sure I understood your question correctly, but it seems to me that why you are asking why do you need to have spring-context dependency if you are using JSR-330 annotations.

Well, the answer from my point of view is you don't actually need the dependency on Spring if you are using only JSR-330 annotations but in order for them to work, you need some library which understands them and correctly builds the dependency graph for you and spring-context is one of such library.

The reason why it is a runtime dependency is because you can switch this provider at runtime, at least in theory.

Upvotes: 0

heisbrandon
heisbrandon

Reputation: 1220

I think the "basic use case" is referring to XML-based application contexts. That documentation is saying if you aren't directly using Spring libraries in your code, then you won't have to include those libraries in your compilation classpath. This is the case with XML configurations, as everything is Spring related is configured in XML, and therefore is not compiled.

In the quick start you've linked, the author is using annotation-based application context configuration, which would require the Spring libraries to be included both at compile- and runtime.

Sample XML configuration: http://www.springbyexample.org/examples/intro-to-ioc-creating-a-spring-application.html

there should only be a few key points where the application code needs to directly access the IoC container [...]. If you're developing a web application, you may not need to directly access the IoC container at all since it will automatically handle instantiation of your controller and any beans it requires.

I'm not completely familiar with it, but it also looks like you can use JSR330 as you suggested with an XML configuration to autowire beans using annotations. See here. This would allow using annotations, but without the need to include Spring in compile-time configurations.

Upvotes: 5

Max
Max

Reputation: 129

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>

Upvotes: 4

Ervis Zyka
Ervis Zyka

Reputation: 506

If I understand correctly you are basically asking how the dependency injector is initialized and how you can inject the dependencies in your classes. In the quick start example you provided the application context is created manually in the main class.

ApplicationContext context = 
      new AnnotationConfigApplicationContext(Application.class);

According to the documentation

Standalone application context, accepting annotated classes as input - in particular @Configuration-annotated classes, but also plain @Component types and JSR-330 compliant classes using javax.inject annotations. Allows for registering classes one by one using register(Class...) as well as for classpath scanning using scan(String...)

An alternative way to initialize spring is within your web.xml, where you use the ContextLoaderListner which will bootstrap the spring application context for you when the programs starts.

The question about how to start spring in web.xml has already been answered here.

Upvotes: -1

ivanenok
ivanenok

Reputation: 624

You can implement your beans with a dependency on javax.inject (@Named, @Inject) in separate bundle. They will be usable from spring based project or any other container which has their own DI implementation.

Here is sample of reworking spring based components to javax.inject (without splitting project to different bundles) http://www.mkyong.com/spring3/spring-3-and-jsr-330-inject-and-named-example/

Upvotes: -1

Related Questions