Spring context as runtime dependency - java

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

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.

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>

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.

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/

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.

Related

Why does the addition of a dependency in Maven trigger functionality?

I have a simple question: I'm just getting started with Open API 3. For this purpose I have added the following dependency in Maven.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.2.30</version>
</dependency>
With the addition of this dependency, can I access the service via localhost:8082/v3/api-docs without having previously set anything and called a function of the dependency? How can this happen? What is the concept behind this ?
Adding the OpenAPI dependency in your Maven pom.xml just adds the librar(ies) to your project. That's all.
If this were a "traditional" project (like a JSP web app, for example), you'd have to write the code to create the web service (e.g. "localhost:8082/v3/api-docs").
But it sounds like your project might be Spring Boot:
https://developer.ibm.com/technologies/java/tutorials/j-spring-boot-basics-perry/
If you let it, Spring Boot will use its #EnableAutoConfiguration
annotation to automatically configure your application.
Auto-configuration is based on the JARS in your classpath and how
you’ve defined your beans:
Spring Boot uses the JARs you have specified to be present in the CLASSPATH to form an opinion about how to configure certain automatic
behavior. For example, if you have the H2 database JAR in your
classpath and have configured no other DataSource beans, then your
application will be automatically configured with an in-memory
database.
Spring Boot uses the way you define beans to determine how to automatically configure itself. For example, if you annotate your JPA
beans with #Entity, then Spring Boot will automatically configure JPA
such that you do not need a persistence.xml file.
It is called convention over configuration.
Wiki link https://en.wikipedia.org/wiki/Convention_over_configuration

Spring boot - new project

I would like to create a java project (none web) to take advantage of the spring features like dependency injection, transactional data, Autowiring etc,
Some of the features I would like to use:
#Service
#Autowired
#Repository
#Transactional
JdbcTemplate
Stuff I don't need:
Hibernate
#Controller
#Path
I am struggling to create that initial Spring project with the initial configuration
I was wondering if I can create that initial Spring project using the new spring boot integration in eclipse?
if its possible what is the correct modules to select from this screen?
The annotations are included in the org.springframework (spring-context) so if you create the default project you will get a pom with the spring-boot-starter dependency which includes the org.springframework.
Regarding to the JDBC it's included in the spring-boot-starter-jdbc.
I think selecting Aspects from Core for all annotations except #Transactional. For #Transactional you should go within SQL and select dependency for any particular db that you are using like PostgreSQL,MySql,SQL Server etc.
Hope this helps !

Spring interceptors using #configuration

I'v mostly used XML based configuration for applicationContexts. I have a requirement where I need to use #configuration to create my beans using #Bean now.
Brief description of why ?
weblogic deploys a spring web-app "A". A makes calls to B(not spring,not web app-no WEB_INF). B just contains common service calls to external servers. Hence B.jar is bundled into A and A is then deployed on web-logic.
Now i need to use spring beans in B.)
So the options available at this point:
Bundle applicationContext.xml and all the property files into B.jar. (keep in mind it is a very complex build process with 20 property files and 100s of beans. So I also need to register propertymanager bean etc..). Then initialize appcontext in a static initializer block and look for appcontext within B.jar.
Use #configuration to register an Appconfig.class instead of an XML. (no changes to build process here).
With this option i need to use a clientInterceptor. Could you provide me with the #Bean definition of this.
How do I configure clientInterceptor in #appconfig.class.
*please let me know if there any other options.
Spring-ws-core - 2.1.4.release
spring-core-3.2.4
expression,context,beans - 3.0.5
spring-oxm-1.0.3
weblogic - 12c
jdk - 1.7
This is my first post here. Any suggestions would be welcome and appreciated. Apologize for any forum faux paus.

Jersey with Spring 4 Dependency Injection

I am to use Dependency Injection of Spring framework version 4. I have seen that the Jersey has its DI with plugin
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.12</version>
</dependency>
Is Jersey's DI of Spring recommended or is there special reason to use it? What if Spring 4 DI is used independently ?
Also please let me know any step by step learning source to integration Spring DI with Jersey ?
The jersey-spring3 extension is not a stand-alone Dependency Injection feature, it's just an extension which makes Jersey aware of Spring's managed beans.
From Jersey - Spring DI:
Jersey provides an extension to support Spring DI. This enables Jersey to use Spring beans as JAX-RS components (e.g. resources and providers) and also allows Spring to inject into Jersey managed components.
...
The above module does not add any transitive dependency to Spring modules, so you will need to add Spring 3 dependencies explicitly into your dependency list.
So if you want to use Jersey with Spring you need jersey-spring3 and all the Spring dependencies you normally use.
By the way, the jersey-spring3 extension is compiled against Spring 3, but should work with Spring 4. See Using Jersey-spring with Spring 4.0 for reference.
You should add jersey-spring3.jar first like the document in jersey website.
For this step by step learning source to integration Spring DI with Jersey, you can do like this when you start up you application debug the application.
Find ServletContainer.class and set a breakpoint in init() function, as this you can find this step by step.

Autowired Dependency Injection with Spring Security

I have a spring webapp with annotation driven configuration.
All Controllers, Repositories are autowired.
When integrating Spring Security I defined a separate security-app.xml. I created a Service called LoginUserService which implements UserDetailsService. Now the method loadUserByUsername() method of this class gets invoked for authentication.
This class has an autowired dependency for UserRepository. Now this autowired dependency turns out to be null. To fix this I enable annotation driven configuration and add the package name for the repository class in component scan configuration.
This solution is also discussed here
spring security with custom user details
But now the problem is that the UserRepository has an EntityManager field with #PersistenceContext annotation. For the spring security configuration it is able to locate the UserRepository but not able to locate the entity manager. Should I create a new EntityManagerFactory here? I guess that will create two persistence units in my application?
How can I inject an autowired dependency to UserRepository created with the original servlet xml?
Update
This is briefly discussed here:
https://stackoverflow.com/a/7078395/161628
But I guess a canonical detailed answer will be more useful to me.
Update
How about using ApplicationContext to get the UserRepository at runtime?
if (userRepository == null) {
userRepository = ApplicationContextProvider.getApplicatonContext().getBean(UserRepository.class);
}
Why is Spring's ApplicationContext.getBean considered bad?
EDIT: Beans that you declare in your config for your DispatcherServlet are not going to be available to any beans you declare or component scan in your contextConfigLocation config files. So in this case, if you're setting up your JPA config in your config file that you load for your DispatcherServlet there is no way to wire that in to beans your declare in your security config. You need to move any "core" bean config like that (datasource config, db connection pool config, JPA/Hibernate config, repository/service component scanning, etc.) into a config file that you load via the contextConfigLocation. Then that stuff will be available both to your security beans and your MVC beans. I think generally the idea is to only load MVC specific beans in your DispatcherServlet config (e.g. Controllers, views, request handlers, request scoped beans, etc.). That way you ensure you have a clean separation between MVC code and non-MVC code, with only a one-way dependency from the MVC code to the "core" code, and no dependencies on MVC code in your "core" code. This helps make your code more modular, and makes it easier to reuse your "core" code in other ways, specifically in unit tests.
(Original comment text was asking about how the security config is loaded, if it's in the contextConfigLocation or somewhere else.)

Categories

Resources