Spring overview
Spring is a lightweight open source framework for layered Java SE/EE application full stack, with IOC (Inverse Of Control) and AOP (Aspect Oriented Programming) as the kernel.
It provides many enterprise application technologies such as presentation layer spring MVC, persistence layer spring JDBC template and business layer transaction management. In short, it simplifies java development. It can also integrate many famous third-party frameworks and class libraries in the world, and gradually become the most used open source framework for Java EE enterprise applications.
Here we need to understand several basic concepts
-
Inversion of control: it is not a technology, but a design idea to reduce the coupling relationship between objects. In Java development, Ioc means giving objects to container control
The most common method is called Dependency Injection (DI) and the other is called Dependency Lookup
Dependency injection: it means that the container is responsible for creating and maintaining dependencies between objects, rather than creating and solving its own dependencies through the object itself. Objects of other classes need to be used in the current class, which are provided by Spring (that is, new is omitted). We only need to explain it in the configuration.
-
Aspect oriented programming: my understanding: extract the same code. For example, all content in the background needs to be logged in. The method to judge whether to log in is aspect oriented programming
- Function: during the running of the program, enhance the function of the method without modifying the source code.
Origin of ioc and dependency injection
We know that in the object-oriented design software system, its bottom layer is composed of N objects. Each object cooperates with each other to finally realize the systematic business logic. For example, a pocket watch has multiple independent gears, which mesh with each other and work together to complete a task. We can see that in such a gear set, if there is a problem with one gear, it may affect the normal operation of the whole gear set. This is the very close coupling relationship. Therefore, in order to solve this problem, software expert Michael Mattson proposed IOC theory in 1996 to realize the "decoupling" between objects. At present, this theory has been successfully applied to practice.
IOC is the abbreviation of Inversion of Control, and most books translate it into "control inversion". The view of IOC theory is generally as follows: decoupling between dependent objects with the help of "third party". As shown below:
As you can see, due to the introduction of the "third party" in the middle, that is, the IOC container, there is no coupling relationship between the four objects A, B, C and D. the transmission between gears all depends on the "third party", and the control of all objects is handed over to the "third party" IOC container. Therefore, the IOC container has become the key core of the whole system, It plays A role similar to "adhesive" and binds all objects in the system together. Without this "adhesive", objects will lose contact with each other. This is the reason why some people compare IOC container to "adhesive".
Let's do another experiment: remove the IOC container in the middle of the figure above, and then take a look at the system:
The picture we see now is all that we need to complete to realize the whole system. At this time, the four objects A, B, C and d have no coupling relationship and no connection with each other. In this way, when you implement A, you don't need to consider B, C and D at all, and the dependency between objects has been reduced to the minimum. Therefore, if the IOC container can be implemented, it will be A wonderful thing for system development. Each member participating in the development only needs to implement his own class, which has nothing to do with others!
Let's take a look at why the inversion of control (IOC) has such a name? Let's compare:
-
Before the software system introduces the IOC container, as shown in Figure 1, object A depends on object B. when object A initializes or runs to A certain point, it must actively create object B or use the created object B. Whether you create or use object B, control is in your own hands.
-
This situation is completely changed after the software system introduces the IOC container. As shown in Figure 3, due to the addition of the IOC container, the direct connection between object A and object B is lost. Therefore, when object A runs to the point where object B is needed, the IOC container will actively create an object B and inject it into the place where object A needs.
Through the comparison before and after, it is not difficult to see that the process of object A obtaining dependent object B changes from active behavior to passive behavior, and the control right is reversed. This is the origin of the name "control reversal".
In 2004, Martin Fowler discussed the same question. Since IOC is control reversal, what aspects of control have been reversed? After detailed analysis and demonstration, he came to the answer: "the process of obtaining dependent objects has been reversed". After the control is reversed, the process of obtaining dependent objects is changed from self-management to active injection by IOC container. Therefore, he gave "inversion of control" a more appropriate name called "Dependency Injection". His answer actually gives a way to implement IOC: injection. The so-called Dependency Injection means that the IOC container dynamically injects certain dependencies into objects during operation.
Therefore, dependency injection (DI) and inversion of control (IOC) describe the same thing from different angles, that is, decoupling between objects by introducing IOC container and using dependency injection.
Advantages of Spring
1) Convenient decoupling and simplified development
Through the IOC container provided by Spring, the dependencies between objects can be controlled by Spring to avoid excessive coupling caused by hard coding.
Users do not have to write code for the very low-level requirements such as singleton pattern class and attribute file parsing, and can focus more on the upper-level applications.
2) AOP programming support
Through the AOP function of Spring, it is convenient for aspect oriented programming. Many functions that are not easy to be realized with traditional OOP can be easily realized through AOP.
3) Declarative transaction support
It can free us from the monotonous and boring transaction management code, and carry out transaction management flexibly in a declarative way, so as to improve the development efficiency and quality
4) Facilitate program testing
Almost all testing work can be carried out in a container independent programming way. Testing is no longer an expensive operation, but a thing to do at will.
Spring architecture
Spring configuration file = > IOC container
Bean tag basic configuration
Function: assign the creation of objects to the Spring container for management through configuration.
By default, it calls the parameterless constructor in the class. If there is no parameterless constructor, it cannot be created successfully.
Related properties
- id: the unique identifier of the Bean instance in the Spring container;
- class: the fully qualified name of the Bean.
Bean tag range configuration
Scope refers to the scope of the object. The values are as follows:
Value range | explain |
---|---|
singleton | Default, singleton |
prototype | Multiple cases |
request | In the WEB project, Spring creates a Bean object and stores the object in the request field |
session | In the WEB project, Spring creates a Bean object and stores the object in the session domain |
global session | In the WEB project, the application is in the Portlet environment. If there is no Portlet environment, the global session is equivalent to the session |
When the value of scope is singleton
- Number of instantiations of Bean: 1
- Bean instantiation timing: instantiate the configured bean instance when the Spring core file is loaded
- Bean lifecycle:
- Object creation: when the application loads and creates a container, the object is created;
- Object running: as long as the container is, the object will always be alive;
- Object destruction: when the application unloads and destroys the container, the object is destroyed.
When the value of scope is prototype
- Number of Bean instantiations: multiple
- Instantiation timing of Bean: instantiate Bean when calling getBean() method
- Bean lifecycle:
- Object creation: create a new object instance when using an object;
- Object running: as long as the object is in use, it will always be alive;
- Object destruction: when an object is not used for a long time, it is recycled by the Java garbage collector.
bean lifecycle configuration
Init method: Specifies the name of the initialization method in the class
Destroy method: Specifies the name of the destroy method in the class
There are three ways to instantiate bean s
Instantiate using the parameterless construction method
Create a class object according to the default parameterless constructor. If there is no default parameterless constructor in the bean, the creation will fail.
<bean id="userDao" class="com.qfedu.dao.impl.UserDaoImpl">
Factory static method instantiation
Create static factory
public class StaticBeanFactory { public static UserDao getUserDaoImpl() { return new UserDaoImpl(); } }
Configure in the Spring configuration file
<!-- Static factory initialization --> <bean id="userDao" class="com.qfedu.factory.StaticBeanFactory" factory-method="getUserDaoImpl"></bean>
test
//Demonstrates how to create a Bean through a static factory @Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) context.getBean("userDao"); userDao.save(); }
Factory instance method instantiation
Create dynamic factory
public class DynamicBeanFactory { public UserDao getUserDao() { return new UserDaoImpl(); } }
Configure in the Spring configuration file
<bean id="factory" class="com.qfedu.factory.DynamicBeanFactory"></bean> <bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
The test is the same as above
DI (dependency injection)
Dependency Injection: Dependency Injection means that the container is responsible for creating and maintaining dependencies between objects, rather than creating and solving its own dependencies through the object itself. Objects of other classes need to be used in the current class, which is provided by Spring. We only need to explain it in the configuration.
The dependencies between the business layer and the persistence layer are maintained by Spring after using Spring.
Simply put, it means waiting for the framework to transfer the persistence layer object to the business layer without getting it ourselves.
That is, the private UserDao userDao = new object () in the service becomes private UserDao userDao;, Omit new
Construction method injection
- Create interface UserService and implementation class UserServiceImpl
public interface UserService { void save(); } public class UserServiceImpl implements UserService { //There must be this attribute here. Our ultimate goal is to associate this attribute with a UserDaoImpl object private UserDao userDao; public UserServiceImpl() { } //There must be a parameterized construction method to complete dependency injection public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } }
- Configure in the Spring configuration file
<bean id="userDao" class="com.qfedu.dao.impl.UserDaoImpl"></bean> <bean id="userService" class="com.qfedu.service.impl.UserServiceImpl"> <!-- Construction method injection, through ref take id For“ userDao"of bean Passed on to UserServiceImpl Of construction method userDao Formal parameter --> <constructor-arg name="userDao" ref="userDao" /> </bean>
- test
@Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); UserService userService = (UserService)context.getBean("userService"); userService.save(); }
set method injection (key)
Add the set method in UserServiceImpl
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
Configure in the Spring configuration file
<bean id="userService" class="UserServiceImpl"> <!-- set Method injection --> <property name="userDao" ref="userDao"></property> </bean>
The test method is the same as above
p namespace injection
The essence of p namespace injection is also set method injection, but it is more convenient than the above set method injection, which is mainly reflected in the configuration file
Introduce P namespace
xmlns:p="http://www.springframework.org/schema/p"
Configure in the Spring configuration file
<!-- p Namespace injection --> <bean id="userService" class="com.qfedu.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
Dependency injection other types
In the above case, we learned how to inject data of reference type. In addition to reference data type, common data type and collection data type, we can also inject data.
Common data type injection
Create Department entity class
//Entity class representing Department public class Department { private Integer id;//Department number private String name;//Department name private String desc;//Department description //set and get methods //toString method }
- Configure in the Spring configuration file
<!-- adopt Spring of IOC Container creation Department Class and inject values into its properties Parameterless construction method instantiation --> <bean id="department" class="com.qfedu.entity.Department"> <!-- set Method injection value: Simple type --> <property name="id" value="1" /> <property name="name" value="R & D department" /> <property name="desc" value="Project R & D" /> </bean>
test
@Test public void test6() { //Parsing the configuration file -- creating objects -- the objects are handed over to Spring's IOC container for management ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //Gets the object of the Department Department department = (Department)context.getBean("department"); //Print object System.out.println(department); }
Reference type injection
- Create entity class Department
//Entity class representing Department public class Department { private Integer id;//Department number private String name;//Department name private String desc;//Department description private Address address;//Department address //set,get //toString }
Configure in the Spring configuration file
<bean id="address" class="com.qfedu.entity.Address"> <property name="province" value="Shandong Province" /> <property name="city" value="Qingdao" /> <property name="county" value="Shibei District" /> <property name="street" value="Longcheng Road" /> <property name="no" value="31 number" /> </bean> <!-- adopt Spring of IOC Container creation Department Class and inject values into its properties Parameterless construction method instantiation --> <bean id="department" class="com.qfedu.entity.Department"> <!-- set Method injection value: Simple type --> <property name="id" value="1" /> <property name="name" value="R & D department" /> <property name="desc" value="Project R & D" /> <!-- set Method injection ref: reference type --> <property name="address" ref="address" /> </bean>
The test is the same as above
Injection of set data type (list < string >)
Create Employee entity class
//Represents the entity class of the employee public class Employee { private Integer id;//Employee number private String name;//full name private Integer age;//Age private String gender;//Gender private List<String> hobby;//hobby //set and get methods //toString method }
- Configure in the Spring configuration file
<!-- adopt Spring of IOC Container creation Employee Class and inject values into its properties Parameterless construction method instantiation --> <bean id="e1" class="com.qfedu.entity.Employee"> <property name="id" value="1" /> <property name="name" value="zs" /> <property name="age" value="30" /> <property name="gender" value="male" /> <!-- Collection type injection --> <property name="hobby"> <list> <value>Learning 1</value> <value>Learning 2</value> <value>Learning 3</value> </list> </property> </bean>
The test is the same as above
Injection of collection data type (list < Object >)
- Modify Department entity class
//Entity class representing Department public class Department { private Integer id;//Department number private String name;//Department name private String desc;//Department description private Address address;//Department address private List<Employee> emps;//Ordinary staff //set and get methods //toString method }
- Configure in the Spring configuration file
<bean id="e1" class="com.qfedu.entity.Employee"> <property name="id" value="1" /> <property name="name" value="zs" /> <property name="age" value="30" /> <property name="gender" value="male" /> <!-- Collection type injection --> <property name="hobby"> <list> <value>Learning 1</value> <value>Learning 2</value> <value>Learning 3</value> </list> </property> </bean> <bean id="e2" class="com.qfedu.entity.Employee"> <property name="id" value="1" /> <property name="name" value="ls" /> <property name="age" value="31" /> <property name="gender" value="male" /> <!--Collection type injection --> <property name="hobby"> <list> <value>Mountain climbing</value> <value>Swimming</value> <value>Online games</value> </list> </property> </bean> <bean id="department" class="com.qfedu.entity.Department"> <!-- set Method injection value: Simple type --> <property name="id" value="1" /> <property name="name" value="R & D department" /> <property name="desc" value="Project R & D" /> <!-- set Method injection ref: reference type --> <property name="address" ref="address" /> <property name="emps"> <list> <ref bean="e1" /> <ref bean="e2" /> </list> </property> </bean>
The test is the same as above
Injection of collection data type (map < string >)
- Modify Department and add properties
//Entity class representing Department public class Department { private Integer id;//Department number private Map<String, Employee> leader;//Department head //set,get //toString }
- Configure in the Spring configuration file
<bean id="e1" class="com.qfedu.entity.Employee"> <property name="id" value="1" /> </bean> <bean id="e2" class="com.qfedu.entity.Employee"> <property name="id" value="2" /> </bean> <bean id="department" class="com.qfedu.entity.Department"> <property name="id" value="1" /> <property name="leader"> <map> <entry key="CEO" value-ref="e1" /> <entry key="CTO" value-ref="e2" /> </map> </property> </bean>
The test is the same as above
Injection of collection data types (properties)
Create the entity class JdbcConfig and add Properties
package com.qfedu.entity; import java.util.Properties; public class JdbcConfig { private Properties config; public Properties getConfig() { return config; } public void setConfig(Properties config) { this.config = config; } @Override public String toString() { return "JdbcConfig{" + "config=" + config + '}'; } }
Configure in the Spring configuration file
<bean id="jdbcConfig" class="com.qfedu.entity.JdbcConfig"> <!-- Properties Type injection --> <property name="config"> <props> <prop key="driverName">com.mysql.jdbc.Driver</prop> <prop key="url">jdbc:mysql://localhost:3306/test</prop> <prop key="username">root</prop> <prop key="password">root</prop> </props> </property> </bean>
test
@Test public void test8() { //Parsing the configuration file -- creating objects -- the objects are handed over to Spring's IOC container for management ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //Get the object of Employee JdbcConfig config = (JdbcConfig)context.getBean("jdbcConfig"); //Print object System.out.println(config); }
Import other profiles
In actual development, there are many Spring configurations, which leads to the complexity and volume of Spring configuration. Therefore, some configurations can be disassembled into other configuration files, and loaded in the main Spring configuration file through the import tag.
<import resource="applicationContext-xxx.xml"/>