1. Overview
2. Spring IO Platform
3. Spring Framework
4. Environment Setup
5. Inversion of Control
6. Dependency injection
7. Spring Web MVC Framework
8. Spring Security
Spring is the most popular application development framework for enterprise Java. Millions of developers around the world use Spring Framework to create high performing, easily testable, reusable code.
October 2002 | The first version was released |
June 2003 | The framework was first released under the Apache 2.0 license |
March 2004 | The first milestone release - 1.0 |
October 2006 | Spring 2.0 |
November 2007 | Spring 2.5 |
December 2009 | Spring 3.0 |
December 2011 | Spring 3.1 |
December 2012 | Spring 3.2 |
December 2013 | Spring 4.0 |
Spring Framework | Provides core support for dependency injection, transaction management, web apps, data access, messaging and more. |
Spring Security | Protects your application with comprehensive and extensible authentication and authorization support. |
Groovy | Brings high-productivity dynamic language features to the JVM. |
Reactor | A foundation for reactive fast data applications on the JVM. |
Spring IO addresses modern data landscape — whether it be document, graph, key-value, relational, or simply unstructured files.
Integration | Channels, Adapters, Filters, Transformers |
Batch | Jobs, Steps, Readers, Writers |
Big data | Ingestion, Export, Orchestration, Hadoop |
Web | Controllers, REST, WebSocket |
Spring is the most popular application development framework for enterprise Java.
The core features of the Spring Framework can be used in developing any Java application, but there are extensions for building web applications on top of the Java EE platform.
Spring enables you to build applications from “plain old Java objects” (POJOs) and to apply enterprise services non-invasively to POJOs. This capability applies to the Java SE programming model and to full and partial Java EE.
https://github.com/soaserele/spring-tutorial/tree/master/hello
The Spring container is at the core of the Spring Framework.
The Spring container uses dependency injection (DI) to manage the components that make up an application.
The container will create the objects, wire them together, configure them, and manage their complete lifecycle from creation till destruction.
The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata provided. The configuration metadata can be represented either by XML, Java annotations, or Java code.
This is the simplest container providing basic support for DI. There are a number of implementations of the BeanFactory interface that come supplied straight out-of-the-box with Spring. The most commonly used BeanFactory implementation is the XmlBeanFactory class.
The ApplicationContext includes all functionality of the BeanFactory, it is generally recommended over the BeanFactory. It adds more enterprise-specific functionality such as the ability to resolve textual messages from a properties file and the ability to publish application events to interested event listeners.
https://github.com/soaserele/spring-tutorial/tree/master/beanfactory
The objects that form the backbone of your application and that are managed by the Spring IoC container are called beans.
A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. These beans are created with the configuration metadata that you supply to the container, for example, in the form of XML <bean/> definitions which you have already seen in previous chapters.
The bean definition contains the information called configuration metadata which is needed for the container to know the followings:
Property | Description |
---|---|
class* | The bean class to be used to create the bean. |
name | The unique bean identifier. |
scope | The scope of the objects created from a particular bean definition. |
autowiring mode | Used to specify autowire mode for a bean definition |
lazy-initialization mode | Tells the IoC container to create a bean instance when it is first requested, rather than at startup. |
Property | Description |
---|---|
constructor-arg | Used to inject the dependencies into the class through a class constructor |
properties | Used to inject the dependencies into the class through setter methods |
Property | Description |
---|---|
initialization method | A callback to be called just after all necessary properties on the bean have been set by the container. |
destruction method | A callback to be used when the container containing the bean is destroyed. |
https://github.com/soaserele/spring-tutorial/tree/master/beandef
Scope | Description |
---|---|
singleton | This scopes the bean definition to a single instance per Spring IoC container (default). |
prototype | This scopes a single bean definition to have any number of object instances. |
request * | This scopes a bean definition to an HTTP request. |
session * | This scopes a bean definition to an HTTP session. |
global-session * | This scopes a bean definition to a global HTTP session. |
https://github.com/soaserele/spring-tutorial/tree/master/beanscope
https://github.com/soaserele/spring-tutorial/tree/master/beaninherit
The life cycle of a Spring bean is easy to understand.
When a bean is instantiated, it may be required to perform some initialization to get it into a usable state.
When the bean is no longer required and is removed from the container, some cleanup may be required.
void afterPropertiesSet() throws Exception;
<bean id="..." class="..." init-method="init"/>
@PostConstruct public void init() { ... }
void destroy() throws Exception;
<bean id="..." class="..." destroy-method="destroy"/>
@PreDestroy public void destroy() { ... }
Methods annotated with @PostConstruct
afterPropertiesSet() as defined by the InitializingBean callback interface
A custom configured init() method
Methods annotated with @PreDestroy
destroy() as defined by the DisposableBean callback interface
A custom configured destroy() method
https://github.com/soaserele/spring-tutorial/tree/master/beanlife
When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while doing unit testing.
Dependency Injection (or sometime called wiring) helps in gluing these classes together and same time keeping them independent.
Type | Description |
---|---|
Constructor-based | Constructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on other class. |
Setter-based | Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean. |
Constructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on other class.
Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean.
https://github.com/soaserele/spring-tutorial/tree/master/ditypes
Scope | Description |
---|---|
no | No autowiring. You should use explicit bean reference for wiring. |
byName | Autowiring by property name. Spring container looks at the properties of the beans on which autowire attribute is set to byName in the XML configuration file. |
byType | Autowiring by property datatype. Spring container looks at the properties of the beans on which autowire attribute is set to byType in the XML configuration file. |
constructor | Similar to byType, but type applies to constructor arguments. |
autodetect
|
Spring first tries to wire using autowire by constructor, if it does not work, Spring tries to autowire by byType.
|
https://github.com/soaserele/spring-tutorial/tree/master/autowire
Starting from Spring 2.5 it became possible to configure the dependency injection using annotations. So instead of using XML to describe a bean wiring, you can move the bean configuration into the component class itself by using annotations on the relevant class, method, or field declaration.
Annotation injection is performed before XML injection, thus the latter configuration will override
the former for properties wired through both approaches.
Annotation wiring is not turned on in the Spring container by default. So, before we can use annotation-based wiring, we will need to enable it in our Spring configuration file. So consider to have following configuration file in case you want to use any annotation in your Spring application.
<?xml version="1.0" encoding="UTF-8"?> <beans
xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> </beans>
@Autowired | The @Autowired annotation can apply to bean property setter methods, non-setter methods, constructor and properties. |
@Qualifier | The @Qualifier annotation along with @Autowired can be used to remove the confusion by specifiying which exact bean will be wired. |
@Required | The @Required annotation applies to bean property setter methods. |
JSR-250 Annotations | Spring supports JSR-250 based annotations which include @Resource, @PostConstruct and @PreDestroy annotations. |
Java based configuration option enables you to write most of your Spring configuration without XML but with the help of few Java-based annotations explained below.
Annotating a class with the @Configuration indicates that the class can be used by the Spring IoC container as a source of bean definitions.
The @Bean annotation tells Spring that a method annotated with @Bean will return an object that should be registered as a bean in the Spring application context.
The Spring web MVC framework provides model-view-controller architecture and ready components that can be used to develop flexible and loosely coupled web applications.
The MVC pattern results in separating the different aspects of the application (input logic, business logic, and UI logic), while providing a loose coupling between these elements.
AppInitializer.java
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
ServletRegistration.Dynamic dispatcher = servletContext.addServlet( "DispatcherServlet", new DispatcherServlet(context)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.do");
servletContext.addListener(new ContextLoaderListener(context));
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context =
new AnnotationConfigWebApplicationContext();
context.setConfigLocation("teach.webhello.config");
return context;
}
}
AppConfig.java
@Configuration @ComponentScan("teach.webhello.config")
public class AppConfig {
}
WebConfig.java
@Configuration
@EnableWebMvc
@ComponentScan("teach.webhello.controller")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
DispatcherServlet delegates the request to the controllers to execute the functionality specific to it.
The @Controller annotation indicates that a particular class serves the role of a controller.
The @RequestMapping annotation is used to map a URL to either an entire class or a particular handler method.
The class-level usage of@RequestMapping indicates that all handling methods on this controller are relative to his path.
HelloController.java
@Controller
public class HelloController {
@RequestMapping("/index")
public String hello(ModelMap model) {
model.addAttribute("date", new Date());
return "hello";
}
}
Spring MVC supports many types of views for different presentation technologies. These include - HTML, PDF, Excel, XML, Velocity, JSON, Atom/RSS feeds, JasperReports etc. But most commonly we use JSP templates written with JSTL.
hello.jsp:
<html>
<head>
<title>Home page</title>
</head>
<body>
<h1>${message}</h1>
<p>Today is: ${date}</p>
</body>
</html>
URI templates can be used for convenient access to selected parts of a URL in a @RequestMapping method.
A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the template becomes a URI.
For example, the URI Template http://www.example.com/users/{userId} contains the variable userId. Assigning the value fred to the variable yields http://www.example.com/users/fred.
@RequestMapping(value = "/users/{userId}", method = RequestMethod.GET) public String findUser(@PathVariable String userId, Model model) { User user = userService.findById(userId); model.addAttribute("user", user); return "displayUser"; }
@Controller
@RequestMapping(value = "/users/{userId}")
public class UsersController {
@RequestMapping(value = "/docs/{docId}", method = RequestMethod.GET) public String findDoc(@PathVariable String userId,
@PathVariable String docId,
Model model) { ... }
}
@RequestMapping(value = "/users/{userId:[a-z-]+}")
public String findUser(@PathVariable String userId, Model model) {
...
}
// GET /pets/42;q=11;r=22 @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET) public void findPet(@PathVariable String petId, @MatrixVariable int q) { // petId == 42 // q == 11 }
// GET /owners/42;q=11/pets/21;q=22 @RequestMapping(value = "/owners/{ownerId}/pets/{petId}") public void findPet(@MatrixVariable(value="q" pathVar="ownerId") int q1,
@MatrixVariable(value="q" pathVar="petId") int q2) { // q1 == 11 // q2 == 22 }
@Controller @RequestMapping(value = "/pets", method = RequestMethod.POST,
consumes = "application/json") public void addPet(@RequestBody Pet pet, Model model) { ... }
@Controller @RequestMapping(value = "/pets/{petId}", method = RequestMethod.POST,
produces = "application/json")
@ResponseBody
public void addPet(@PathVariable String petId, Model model) { ... }
The Configuration object is the first Hibernate object you create in any Hibernate application and usually created only once during application initialization. It represents a configuration or properties file required by the Hibernate.
Configuration object is used to create a SessionFactory object which inturn configures Hibernate and allows for a Session object to be instantiated. The SessionFactory is a thread safe object and used by all the threads of an application.
A Session is used to get a physical connection with a database. The Session object is lightweight and designed to be instantiated each time an interaction is needed with the database.
A Transaction represents a unit of work with the database and most of the RDBMS supports transaction functionality. Transactions in Hibernate are handled by an underlying transaction manager and transaction (from JDBC or JTA)
Query objects use SQL or Hibernate Query Language (HQL) string to retrieve data from the database and create objects. A Query instance is used to bind query parameters, limit the number of results returned by the query, and finally to execute the query.
Criteria object are used to create and execute object oriented criteria queries to retrieve objects.
@Value("${jdbc.driverClassName}") | private String driverClassName; |
@Value("${jdbc.url}") | private String url; |
@Value("${jdbc.username}") | private String username; |
@Value("${jdbc.password}") | private String password; |
@Value("${hibernate.dialect}") | private String hibernateDialect; |
@Value("${hibernate.show_sql}") | private String hibernateShowSql; |
@Value("${hibernate.hbm2ddl.auto}") | private String hibernateHbm2ddlAuto; |
@Configuration @EnableWebMvcSecurity @EnableGlobalMethodSecurity(securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception { auth.inMemoryAuthentication() .withUser("user").password("user").roles("USER") .and() .withUser("admin").password("admin").roles("USER", "ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().authenticated(); } }
http.authorizeRequests()
.antMatchers(
"/news/add.do",
"/news/delete/**",
"/comments/delete/**"
).hasRole("ADMIN")
.antMatchers(
"/comments/add/**"
).hasRole("USER")
.anyRequest().permitAll()
<ul class="nav pull-right">
<sec:authorize access="hasRole('ROLE_ADMIN')">
<li><a href="/news/add.do">Add news</a></li>
</sec:authorize>
<sec:authorize access="isAnonymous()">
<li><a href="/login.do">Login</a></li>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<li><a href="/logout">Logout</a></li>
</sec:authorize>
</ul>
public interface BankService { @Secured("IS_AUTHENTICATED_ANONYMOUSLY") public Account readAccount(Long id); @Secured("ROLE_TELLER") public Account post(Account account, double amount); }
public interface BankService { @PreAuthorize("isAnonymous()") public Account readAccount(Long id); @PreAuthorize("hasAuthority('ROLE_TELLER')") public Account post(Account account, double amount); }