Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring context as runtime dependency

Tags:

java

spring

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"?

like image 876
user2418306 Avatar asked Feb 25 '16 14:02

user2418306


2 Answers

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.

like image 183
heisbrandon Avatar answered Sep 22 '22 00:09

heisbrandon


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>
like image 34
Max Avatar answered Sep 24 '22 00:09

Max