Project management and SSM framework - Spring

Spring



1. Introduction to Spring

1. Introduction to Spring

insert image description here
Spring is an open source framework born to simplify enterprise-level development. It takes IOC (Inversion of Control) and AOP (Aspect-Oriented) as the core of thought, provides many technologies such as control layer SpringMVC, data layer SpringData, service layer transaction management, and can integrate many third-party frameworks.

Spring makes many complicated codes elegant and concise, effectively reduces the coupling degree of codes, and greatly facilitates the later maintenance, upgrade and expansion of projects.

2. Spring architecture

insert image description here
The Spring framework is divided into multiple modules according to different functions. These modules can meet the needs of all enterprise-level application development. During the development process, the required modules can be selectively used according to the requirements.

Core Container : The core module of Spring. The use of any function is inseparable from this module, which is the basis for other modules.
Data Access/Integration : This module provides corresponding functions for data persistence.
Web : This module provides corresponding functions for web development.
AOP : Provides an aspect-oriented programming implementation
Aspects : Provides integration with the AspectJ framework, which is an aspect-oriented programming framework.
Instrumentation : Provides the support of class tools and the implementation of class loaders, which can be used in specific application servers.
Messaging : Integrate some basic messaging applications for the Spring framework
Test : Provide integration with the test framework

2. Spring IOC

1. Inversion of control thinking

IOC (Inversion of Control): The program hands over the right to create objects to the framework.

In the previous development process, the creation of object instances was managed by the caller, the code is as follows:

1public interface StudentDao {
    
    
2    // 根据id查询学生
3    Student findById(int id);
4}
5
6public class StudentDaoImpl implements StudentDao{
    
    
7    @Override
8    public Student findById(int id) {
    
    
9        // 模拟从数据库查找出学生
10        return new Student(1,"李星云","长安");
11    }
12}
13
14public class StudentService {
    
    
15    public Student findStudentById(int id){
    
    
16        // 此处就是调用者在创建对象
17        StudentDao studentDao = new StudentDaoImpl();
18        return studentDao.findById(1);
19    }
20}

This way of writing has two disadvantages:

1. Waste of resources: StudentService will create an object when it calls a method, and if it calls the method continuously, it will create a large number of StudentDao objects.

2. High degree of code coupling: Assume that with the development, we have created another more complete implementation class StudentDaoImpl2 of StudentDao. If you want to use StudentDaoImpl2 in StudentService, you must modify the source code.

The IOC idea is to hand over the right to create objects to the framework. The framework will help us create objects and allocate the use of objects. The control right is transferred from the program code to the framework, and the control right is reversed. This is Spring's IOC idea. The IOC idea can perfectly solve the above two problems.

2. Custom object container

insert image description here
Next, we simulate the IOC idea through a piece of code. To create a collection container, first create the object and put it in the container. When you need to use the object, you only need to get the object from the container without recreating it. At this time, the container is the manager of the object.

1. Create an entity class

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String address;
5    // 省略getter/setter/构造方法/tostring
6}

2. Create Dao interface and implementation class

1public interface StudentDao {
    
    
2    // 根据id查询学生
3    Student findById(int id);
4}
5
6public class StudentDaoImpl implements StudentDao{
    
    
7    @Override
8    public Student findById(int id) {
    
    
9        // 模拟从数据库查找出学生
10        return new Student(1,"小猪猪","雅安");
11    }
12}
13
14public class StudentDaoImpl2 implements StudentDao{
    
    
15    @Override
16    public Student findById(int id) {
    
    
17        // 模拟根据id查询学生
18        System.out.println("新方法!!!");
19        return new Student(1,"逍遥","泸州");
20    }
21}

3. Create a configuration file bean.properties, which defines the managed objects

1studentDao=com.itbaizhan.dao.StudentDaoImpl

4. Create a container management class, which reads the configuration file when the class is loaded, and creates and puts all the objects configured in the configuration file into the container.

1public class Container {
    
    
2    static Map<String,Object> map = new HashMap();
3
4    static {
    
    
5        // 读取配置文件
6        InputStream is = Container.class.getClassLoader().getResourceAsStream("bean.properties");
7        Properties properties = new Properties();
8        try {
    
    
9            properties.load(is);
10        } catch (IOException e) {
    
    
11            e.printStackTrace();
12        }
13
14        // 遍历配置文件的所有配置
15        Enumeration<Object> keys = properties.keys();
16        while (keys.hasMoreElements()){
    
    
17            String key = keys.nextElement().toString();
18            String value = properties.getProperty(key);
19            try {
    
    
20                // 创建对象
21                Object o = Class.forName(value).newInstance();
22                // 将对象放入集合中
23                map.put(key,o);
24            } catch (Exception e) {
    
    
25                e.printStackTrace();
26            }
27        }
28    }
29
30    // 从容器中获取对象
31    public static Object getBean(String key){
    
    
32        return map.get(key);
33    }
34}

5. Create the caller StudentService of the Dao object

1public class StudentService {
    
    
2    public Student findStudentById(int id){
    
    
3        // 从容器中获取对象
4        StudentDao studentDao = (StudentDao) Container.getBean("studentDao");
5        System.out.println(studentDao.hashCode());
6        return studentDao.findById(id);
7    }
8}

6. Test the StudentService

1public class Test {
    
    
2    public static void main(String[] args) {
    
    
3      StudentService studentService = new StudentService();
4      System.out.println(studentService.findStudentById(1));
5      System.out.println(studentService.findStudentById(1));
6    }
7}

Test Results:

1. StudentServiceThe same object is obtained from the container every time StudentDao, which saves resources.

2. If you want to use StudentDaoImpl2the object, you only need to modify bean.propertiesthe content as

1 studentDao = com.package.dao.StudentDaoImpl2

No need to modify the Java source code.

3. Spring implements IOC

Next, we use Spring to implement IOC, and there is also a container inside Spring to manage objects.

1. Create a Maven project and introduce dependencies

1<dependencies>
2    <dependency>
3        <groupId>org.springframework</groupId>
4        <artifactId>spring-context</artifactId>
5        <version>5.3.13</version>
6    </dependency>
7    <dependency>
8        <groupId>junit</groupId>
9        <artifactId>junit</artifactId>
10        <version>4.12</version>
11        <scope>test</scope>
12    </dependency>
13</dependencies>

2. Create POJO classes, Dao classes and interfaces

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String address;
5    // 省略getter/setter/构造方法/tostring
6}
7
8public interface StudentDao {
    
    
9    // 根据id查询学生
10    Student findById(int id);
11}
12
13public class StudentDaoImpl implements StudentDao{
    
    
14    @Override
15    public Student findById(int id) {
    
    
16        // 模拟从数据库查找出学生
17        return new Student(1,"锤形态小跑","皮尔特沃夫");
18    }
19}

3. Write the xml configuration file, and configure the objects that Spring needs to create for us in the configuration file.

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4       xsi:schemaLocation="http://www.springframework.org/schema/beans
5        http://www.springframework.org/schema/beans/spring-beans.xsd">
6
7    <bean id="studentDao" class="com.package.dao.StudentDaoImpl"></bean>
8    
9</beans>

4. The test gets the object from the Spring container.

1public class TestContainer {
    
    
2    @Test
3    public void t1(){
    
    
4        // 创建Spring容器
5        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
6        // 从容器获取对象
7        StudentDao studentDao1 = (StudentDao) ac.getBean("studentDao");
8        StudentDao studentDao2 = (StudentDao) ac.getBean("studentDao");
9        System.out.println(studentDao1.hashCode());
10        System.out.println(studentDao2.hashCode());
11        System.out.println(studentDao1.findById(1));
12    }
13}

4. Spring container type

insert image description here

Container interface
BeanFactory : BeanFactory is the top-level interface in the Spring container, which can manage Bean objects.

ApplicationContext: ApplicationContext is a subinterface of BeanFactory. In addition to inheriting all the functions of BeanFactory, it also adds good support for internationalization, resource access, and event propagation.

ApplicationContext has the following three common implementation classes:

Container implementation class
ClassPathXmlApplicationContext : This class can read configuration files from the project
FileSystemXmlApplicationContext: This class reads configuration files from disk
AnnotationConfigApplicationContext: Using this class does not read configuration files, but reads annotations

1@Test
2public void t2(){
    
    
3    // 创建spring容器
4    //        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
5    ApplicationContext ac = new FileSystemXmlApplicationContext("D:\code\webproject\spring\spring_ioc1\src\main\resources\bean.xml");
6    
7    // 从容器中获取对象
8    StudentDao userDao = (StudentDao) ac.getBean("studentDao");
9    System.out.println(userDao);
10    System.out.println(userDao.findById(1));
11}

5. Object creation method

insert image description here
Spring will help us create beans, so what method does it call at the bottom to create them?

Using the construction method
Spring uses the empty parameter construction method of the class to create the bean by default:

1// 假如类没有空参构造方法,将无法完成bean的创建
2public class StudentDaoImpl implements StudentDao{
    
    
3    public StudentDaoImpl(int a){
    
    }
4    
5    @Override
6    public Student findById(int id) {
    
    
7        // 模拟根据id查询学生
8        return new Student(1,"小兔兔","加利福尼亚");
9    }
10}

Using the method of the factory class
Spring can call the method of the factory class to create beans:

1. Create a factory class that provides methods for creating objects:

1public class StudentDaoFactory {
    
    
2    public StudentDao getStudentDao(){
    
    
3        return new StudentDaoImpl(1);
4    }
5}

2. Configure the method of creating beans in the configuration file as the factory method.

1<!--  id:工厂对象的id,class:工厂类  -->
2<bean id="studentDaoFactory" class="com.package.dao.StudentDaoFactory"></bean>
3<!--  id:bean对象的id,factory-bean:工厂对象的id,factory-method:工厂方法 -->
4<bean id="studentDao" factory-bean="studentDaoFactory" factory-method="getStudentDao"></bean>

3. Test

Using the static method of the factory class
Spring can call the static method of the factory class to create beans:

1. Create a factory class, which provides static methods for creating objects.

1public class StudentDaoFactory2 {
    
    
2    public static StudentDao getStudentDao2() {
    
    
3        return new StudentDaoImpl();
4    }
5}

2. Configure the method of creating beans in the configuration file as the factory static method.

1<!-- id:bean的id  class:工厂全类名 factory-method:工厂静态方法   -->
2<bean id="studentDao" class="com.package.dao.StudentDaoFactory2" factory-method="getStudentDao2"></bean>

3. Test

6. Object creation strategy

Spring sets the creation strategy of objects through the attributes <bean>in the configuration. There are five creation strategies:scope

singleton: singleton, default strategy. The entire project will only create one object, and the creation timing of the singleton object can be set through the properties <bean>in :lazy-init

lazy-init="false"(Default): Create immediately, all Bean objects in the configuration file will be created when the container starts.

lazy-init="true": Delayed creation, which will be created when the Bean object is used for the first time.

Configure a singleton strategy:

1<!--    <bean id="studentDao" class="com.package.dao.StudentDaoImpl2" scope="singleton" lazy-init="true"></bean>-->
2<bean id="studentDao" class="com.package.dao.StudentDaoImpl2" scope="singleton" lazy-init="false"></bean>

Test singleton strategy:

1// 为Bean对象的类添加构造方法
2public StudentDaoImpl2(){
    
    
3    System.out.println("创建StudentDao!!!");
4}
5
6@Test
7public void t2(){
    
    
8    // 创建Spring容器
9    ApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
10    // 从容器获取对象
11    StudentDao studentDao1 = (StudentDao) ac.getBean("studentDao");
12    StudentDao studentDao2 = (StudentDao) ac.getBean("studentDao");
13    StudentDao studentDao3 = (StudentDao) ac.getBean("studentDao");
14    System.out.println(studentDao1.hashCode());
15    System.out.println(studentDao2.hashCode());
16    System.out.println(studentDao3.hashCode());
17}

prototype: Multiple instances, objects are created each time they are fetched from the container.

1<!-- 配置多例策略 -->
2<bean id="studentDao"   class="com.package.dao.StudentDaoImpl2" scope="prototype"></bean>

request: An object is created for each request, which is only valid in the web environment.

session: An object is created per session, only valid in the web environment.

gloabal-session: A session in a cluster environment creates an object, which is only valid in the web environment.

7. The timing of object destruction

The creation strategy of the object is different, and the timing of destruction is also different:

singleton: The object is destroyed when the container is destroyed.
prototype: Destroy the object using the JAVA garbage collection mechanism.
request: When processing the request ends, the bean instance will be destroyed.
session: When the HTTP Session is finally discarded, the bean will also be destroyed.
gloabal-session: When the session in the cluster environment is destroyed, the bean instance will also be destroyed.

8. Lifecycle methods

The life cycle of a Bean object includes creation-use-destruction, and Spring can configure the method that the Bean object executes automatically when it is created and destroyed:

1. Define lifecycle methods

1public class StudentDaoImpl2 implements StudentDao{
    
    
2     // 创建时自动执行的方法
3    public void init(){
    
    
4        System.out.println("创建StudentDao!!!");
5    }
6
7    // 销毁时自动执行的方法
8    public void destory(){
    
    
9        System.out.println("销毁StudentDao!!!");
10    }
11}

2. Configure the life cycle method

1<!-- init-method:创建对象时执行的方法  destroy-method:销毁对象时执行的方法  -->
2<bean id="studentDao" class="com.package.dao.StudentDaoImpl2" scope="singleton"
3      init-method="init" destroy-method="destory"></bean>

3. Test

1@Test
2public void t3(){
    
    
3    // 创建Spring容器
4    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
5
6    // 销毁Spring容器,ClassPathXmlApplicationContext才有销毁容器的方法
7    ac.close();
8}

9. The way to get the Bean object

Spring has multiple ways to get objects in the container:

Get by id/name

1. Configuration file

1<bean name="studentDao" class="com.package.dao.StudentDaoImpl2"></bean>
2
3<bean id="studentDao" class="com.package.dao.StudentDaoImpl2"></bean>

2. Get the object

1StudentDao studentDao = (StudentDao) ac.getBean("studentDao");

Get by type

1. Configuration file

1<bean name="studentDao" class="com.package.dao.StudentDaoImpl2"></bean>

2. Get the object

1StudentDao studentDao2 = ac.getBean(StudentDao.class);

It can be seen that using type acquisition does not require forced conversion.

Obtain by type + id/name

Although there is no need to force the type to obtain, if there are multiple implementation class objects of an interface in the container, an error will be reported when obtaining, and you need to use type + id/name to obtain

1. Configuration file

1<bean name="studentDao" class="com.package.dao.StudentDaoImpl2"></bean>
2<bean name="studentDao1" class="com.package.dao.StudentDaoImpl"></bean>

2. Get the object

1StudentDao studentDao2 = ac.getBean("studentDao",StudentDao.class);

3. Dependency Injection

1. What is dependency injection

insert image description here

Dependency Injection (DI for short), which is the concrete implementation of Spring's idea of ​​inversion of control.

Inversion of control hands over the creation of objects to Spring, but objects may depend on other objects. For example, there must be attributes of the dao class in the service class, and we call the service dependent on dao. Previously, it was necessary to manually inject attribute values, the code is as follows:

1public interface StudentDao {
    
    
2    Student findById(int id);
3}
4
5public class StudentDaoImpl implements StudentDao{
    
    
6    @Override
7    public Student findById(int id) {
    
    
8        // 模拟根据id查询学生
9        return new Student(1,"王阳明","绍兴府");
10    }
11}
12
13public class StudentService {
    
    
14    // service依赖dao,手动注入属性值,即手动维护依赖关系
15    private StudentDao studentDao = new StudentDaoImpl();
16
17    public Student findStudentById(int id){
    
    
18        return studentDao.findById(id);
19    }
20}

At this time, when the StudentService wants to use another implementation class of StudentDao such as StudentDaoImpl2, the Java source code needs to be modified, which reduces the maintainability of the code.

After using the Spring framework, Spring manages Service objects and Dao objects. At this time, it can inject dependent Dao attribute values ​​into Service objects. This is Spring's dependency injection. Simply put, inversion of control is to create objects, and dependency injection is to assign values ​​​​to the properties of objects.

2. Dependency injection method

In previous development, object property values ​​can be set through setter methods or construction methods:

1// setter方法设置属性
2StudentService studentService = new StudentService();
3StudentDao studentDao = new StudentDao();
4studentService.setStudentDao(studentDao);
5
6// 构造方法设置属性
7StudentDao studentDao = new StudentDao();
8StudentService studentService = new StudentService(studentDao);

Spring can assign values ​​​​to properties by calling setter methods or constructors

Setter injection

1. The setter method of the injected class to write the attribute

1public class StudentService {
    
    
2    private StudentDao studentDao;
3    public void setStudentDao(StudentDao studentDao) {
    
    
4        this.studentDao = studentDao;
5    }
6}

<bean>2. In the configuration file, set the middle settings that need to inject attribute values<property>

1<bean id="studentDao" class="com.package.dao.StudentDaoImpl"></bean>
2<bean id="studentService" class="com.package.service.StudentService">
3    <!--依赖注入-->
4    <!--name:对象的属性名 ref:容器中对象的id值-->
5    <property name="studentDao/*属性名private 'StudentDao' studentDao;*/" ref="studentDao/*同bean的id*/"></property>
6</bean>

3. Test whether the injection is successful

1@Test
2public void t2(){
    
    
3    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
4    StudentService studentService = (StudentService) ac.getBean("studentService");
5    System.out.println(studentService.findStudentById(1));
6}

constructor injection

1. The injected class writes a constructor with parameters

1public class StudentService {
    
    
2    private StudentDao studentDao;
3    public StudentService(StudentDao studentDao) {
    
    
4        this.studentDao = studentDao;
5    }
6}

2. Set the middle settings that need to inject attribute values

1<bean id="studentDao" class="com.package.dao.StudentDaoImpl"></bean>
2
3<bean id="studentService" class="com.package.service.StudentService">
4    <!-- 依赖注入 -->
5    <!-- name:对象的属性名  ref:配置文件中注入对象的id值 -->
6    <constructor-arg name="studentDao" ref="studentDao"></constructor-arg>
7</bean>

3. Test whether the injection is successful

1@Test
2public void t2(){
    
    
3    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
4    StudentService studentService = (StudentService) ac.getBean("studentService");
5    System.out.println(studentService.findStudentById(1));
6}

automatic injection

Automatic injection does not need to <bean>add other tags to inject attribute values, but automatically finds the corresponding bean object from the container and sets it as the attribute value.

There are two ways to configure automatic injection:

Global configuration: <beans>Setting default-autowireproperties in can define the automatic injection strategy of all bean objects.
Local configuration: <bean>Setting autowireproperties in can define the automatic injection strategy of the current bean object.

The value of autowire is as follows:

no: No automatic injection will take place.
default: The global configuration default is equivalent to no, and the local configuration default means to use the global configuration
byName: find the bean whose id is the same as the property name in the Spring container, and inject it. A set method needs to be provided.
byType: Find the bean of the same type as the property type in the Spring container and inject it. A set method needs to be provided.
constructor: Find the bean whose id is the same as the attribute name in the Spring container and inject it. A constructor is required.

3. Dependency injection type

DI supports injection of bean types, basic data types and strings, List collections, Set collections, Map collections, Properties object types, etc. They are written as follows:

1. Prepare classes for injecting attributes

1public class StudentService {
    
    
2    private StudentDao studentDao; // bean属性
3    private String name; //字符串类型
4    private int count; //基本数据类型
5    private List<String> names; // 字符串类型List集合
6    private List<Student> students1; // 对象类型List集合
7    private Set<Student> students2; // 对象类型Set集合
8    private Map<String,String> names2; // 字符串类型Map集合
9    private Map<String,Student> students3; // 对象类型Map集合
10    private Properties properties; //Properties类型
11    
12    // 省略getter/setter/toString
13}

2. Prepare the test method

1@Test
2public void t3(){
    
    
3    ApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
4    StudentService studentService = (StudentService) ac.getBean("studentService");
5    System.out.println(studentService);
6}

Inject bean type

Writing method one:

1<bean id="studentDao" class="com.package.dao.StudentDaoImpl"></bean>
2
3<bean id="studentService" class="com.package.service.StudentService">
4    <property name="studentDao" ref="studentDao"></property>
5</bean>

Writing method two:

1<bean id="studentDao" class="com.package.dao.StudentDaoImpl"></bean>
2
3<bean id="studentService" class="com.package.service.StudentService">
4    <property name="studentDao" >
5        <ref bean="studentDao"></ref>
6    </property>
7</bean>

Inject primitive data types

1<bean id="studentService" class="com.package.service.StudentService">
2    <!--  写法一 name:属性名  value:属性值-->
3    <property name="name" value="玛卡巴卡"></property>
4
5    <!--  写法二 name:属性名  value:属性值-->
6    <property name="count">
7        <value>10</value>
8    </property>
9</bean>

Inject the List collection

1<bean id="studentService" class="com.package.service.StudentService">
2    <!-- 简单数据类型List集合 name:属性名 -->
3    <property name="names">
4        <list>
5            <value>蚩梦</value>
6            <value>阿姐</value>
7        </list>
8    </property>
9
10    <!-- 对象类型List集合 name:属性名 -->
11    <property name="students1">
12        <list>
13            <bean class="com.package.domain.Student">
14                <property name="id" value="1"/>
15                <property name="name" value="蚩梦"/>
16                <property name="address" value="taoqi"/>
17            </bean>
18            <bean class="com.itbaizhan.domain.Student">
19                <property name="id" value="2"/>
20                <property name="name" value="阿姐"/>
21                <property name="address" value="keai"/>
22            </bean>
23        </list>
24    </property>
25</bean>

Inject the Set collection

1<bean id="studentService" class="com.package.service.StudentService">
2    <!-- Set集合 -->
3    <property name="students2">
4        <set>
5            <bean class="com.package.domain.Student">
6                <property name="id" value="1"/>
7                <property name="name" value="Tom"/>
8                <property name="address" value="myheart"/>
9            </bean>
10            <bean class="com.itbaizhan.domain.Student">
11                <property name="id" value="2"/>
12                <property name="name" value="Jerry"/>
13                <property name="address" value="myhome"/>
14            </bean>
15        </set>
16    </property>
17</bean>

Inject the Map collection

Simple data type Map collection:

1<bean id="studentService" class="com.package.service.StudentService">
2    <property name="names2">
3        <map>
4            <entry key="student1" value="libai"/>
5            <entry key="student2" value="dufu"/>
6        </map>
7    </property>
8</bean>

Object type Map collection:

1<bean id="studentService" class="com.package.service.StudentService">
2    <property name="students3">
3        <map>
4            <entry key="student1" value-ref="s1"/>
5            <entry key="student2" value-ref="s2"/>
6        </map>
7    </property>
8</bean>
9
10<bean id="s1" class="com.package.domain.Student">
11    <property name="id" value="1"/>
12    <property name="name" value="wangyangming"/>
13    <property name="address" value="Chinese"/>
14</bean>
15<bean id="s2" class="com.package.domain.Student">
16    <property name="id" value="2"/>
17    <property name="name" value="heigeer"/>
18    <property name="address" value="earth"/>
19</bean>

Inject the Properties object

1<bean id="studentService" class="com.package.service.StudentService">
2    <property name="properties">
3        <props>
4            <prop key="配置1">1</prop>
5            <prop key="配置2">2</prop>
6        </props>
7    </property>
8</bean>

4. Annotation to realize IOC

1.@Component

Function: used to create objects and put them into the Spring container, which is equivalent to<bean id="" class="">

Location: Above Class

Notice:

To configure the scanned package in the configuration file, the annotation will take effect only after scanning.

1<context:component-scan base-package="com.package"></context:component-scan>

@ComponentThe default id for an annotation configuration bean is the class name with the first letter lowercase. You can also manually set the bean's id value.

1// 此时bean的id为studentDaoImpl
2@Component
3public class StudentDaoImpl implements StudentDao{
    
    
4    public Student findById(int id) {
    
    
5        // 模拟根据id查询学生
6        return new Student(1,"xiaokeai","wherever");
7    }
8}
9
10// 此时bean的id为studentDao
11@Component("studentDao")
12public class StudentDaoImpl implements StudentDao{
    
    
13    public Student findById(int id) {
    
    
14        // 模拟根据id查询学生
15        return new Student(1,"xiaotaoqi","here");
16    }
17}

2.@Repository、@Service、@Controller

Function: These three annotations have @Componentthe same function as , and they are used to distinguish which layer the class belongs to.

Location:

@RepositoryFor Dao layer
@ServiceFor Service layer
@ControllerFor Controller layer

1@Repository
2public class StudentDaoImpl implements StudentDao{
    
    }
3
4@Service
5public class StudentService {
    
    }

3.@Scope

Role: specify the bean creation strategy

Location: Above Class

Value:singleton prototype request session globalsession

1@Service
2@Scope("singleton")
3public class StudentService {
    
    }

4.@Autowired

Function: Find the object that matches the attribute type from the container and automatically inject it into the attribute. Used instead of <bean>dependency injection configuration in .

Position: above the property, above the setter method, above the constructor.

Notice:

1. @AutowiredWhen writing above the property for dependency injection, the setter method can be omitted.

1@Component
2public class StudentService {
    
    
3    @Autowired
4    private StudentDao studentDao;
5    public Student findStudentById(int id){
    
    
6        return studentDao.findById(id);
7    }
8}
9
10@Test
11public void t2(){
    
    
12    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
13    StudentService studentService = (StudentService) ac.getBean("studentService");
14    System.out.println(studentService.findStudentById(1));
15}

2. An error will be reported if there is no object of the corresponding type in the container

1// 如果StudentDaoImpl没有放到容器中会报错
2//@Component("studentDao")
3public class StudentDaoImpl implements StudentDao{
    
    
4    public Student findById(int id) {
    
    
5        // 模拟根据id查询学生
6        return new Student(1,"name","address");
7    }
8}

3. When there are multiple objects matching the type in the container, the object whose beanId is equal to the attribute name will be found, and an error will be reported if it cannot be found.

1// 如果容器中都多个同类型对象,会根据id值等于属性名找对象
2@Component("studentDao")
3public class StudentDaoImpl implements StudentDao{
    
    
4    public Student findById(int id) {
    
    
5        // 模拟根据id查询学生
6        return new Student(1,"peiqi","tonghua");
7    }
8}
9
10@Component
11public class StudentDaoImpl implements StudentDao{
    
    
12    public Student findById(int id) {
    
    
13        // 模拟根据id查询学生
14        return new Student(1,"wangzi","chengbao");
15    }
16}

5.@Qualifier

Function: On the basis of injecting objects according to the type, inject according to the id of the bean.

Position: above the property

Note: @Qualifier must be used together with @Autowired.

1@Component
2public class StudentService {
    
    
3    @Autowired
4    @Qualifier("studentDaoImpl2")
5    private StudentDao studentDao;
6    public Student findStudentById(int id){
    
    
7        return studentDao.findById(id);
8    }
9}

6.@Value

Function: inject attribute values ​​of String type and basic data type.

Position: above the property

usage:

1. Directly set fixed attribute values

1@Service
2public class StudentService {
    
    
3    @Value("1")
4    private int count;
5
6    @Value("hello")
7    private String str;
8}

2. Obtain the attribute value in the configuration file:

(1). Write the configuration file db.properties

1jdbc.username=username1
2jdbc.password=password1

(2). Spring core configuration file scanning configuration file

1<context:property-placeholder location="db.properties"></context:property-placeholder>

(3). Inject the attribute value in the configuration file

1@Value("${jdbc.username}")
2private String username;
3
4@Value("${jdbc.password}")
5private String password;

7.@Configuration

At this point, the annotation-based IOC configuration has been completed, but we still cannot do without Spring's xml configuration file. Next, we break away bean.xmland implement IOC using pure annotations.

In real development, we generally still keep the xml configuration file, and it is more convenient to use the configuration file in many cases.

Pure annotation implementation of IOC requires a Java class instead of an xml file. This Java class needs to be added above @Configuration, indicating that this class is a configuration class, and its function is to replace the configuration file.

1@Configuration
2public class SpringConfig {
    
       
3}

8.@ComponentScan

Role: Specify the package that spring scans when initializing the container.

Location: above the configuration class

1@Configuration
2@ComponentScan("com.package")
3public class SpringConfig {
    
    
4}

9.@Bean

Function: Put the return value object of the method into the Spring container. If you want to put objects of third-party classes into containers, you can use@Bean

Location: above the method of the configuration class.

Attribute: name: set the id for the bean object

Note: @BeanIf the modified method has parameters, spring will look for available objects from the container according to the parameter type.

Example: If we want to put the jdbc connection object into the Spring container, we cannot modify the Connection source code to add it @Component, so we need to use the method to put @Beanthe object into the Spring container

1. Add driver dependencies

1<dependency>
2    <groupId>mysql</groupId>
3    <artifactId>mysql-connector-java</artifactId>
4    <version>8.0.27</version>
5</dependency>

2. Put the Connection object into the Spring container

1@Bean(name = "connection")
2public Connection getConnection(){
    
    
3    try {
    
    
4        Class.forName("com.mysql.cj.jdbc.Driver");
5        return DriverManager.getConnection("jdbc:mysql:///mysql", "username1", "password1");
6    } catch (Exception exception) {
    
    
7        return null;
8    }
9}

3. Test

1@Test
2public void t5(){
    
    
3    ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
4    Connection connection = (Connection) ac.getBean("connection");
5    System.out.println(connection);
6}

10.@Import

Function: If there are too many configurations, there will be multiple configuration classes. This annotation can import other configuration classes for the main configuration class

Location: above the main configuration class

1// Jdbc配置类
2@Configuration
3public class JdbcConfig {
    
    
4    @Bean(name = "connection")
5    public Connection getConnection(){
    
    
6        try {
    
    
7            Class.forName("com.mysql.cj.jdbc.Driver");
8            return DriverManager.getConnection("jdbc:mysql:///mysql", "root", "root");
9        } catch (Exception exception) {
    
    
10            return null;
11        }
12    }
13}
14
15// 主配置类
16@Configuration
17@ComponentScan("com.package")
18@Import(JdbcConfig.class)
19public class SpringConfig {
    
    
20
21}

11.@PropertySource

<context:property-placeholder>Role: replace the scan configuration file in the configuration file

Location: above the configuration class

Note: keywords must be added before the location of the configuration fileclasspath

1@Configuration
2@PropertySource("classpath:db.properties")
3public class JdbcConfig {
    
    
4    @Value("${jdbc.username}")
5    private String username;
6
7    @Value("${jdbc.password}")
8    private String password;
9
10}

5. Spring integrates MyBatis

1. Build the environment

We know that when using MyBatis, we need to write a lot of code to create objects such as SqlSessionFactoryBuilder, SqlSessionFactory, SqlSession, etc., and the role of Spring is to help us create and manage objects, so we can use Spring to integrate MyBatis and simplify MyBatis development.

Create a maven project and introduce dependencies.

1<dependencies>
2    <!--  mybatis  -->
3    <dependency>
4        <groupId>org.mybatis</groupId>
5        <artifactId>mybatis</artifactId>
6        <version>3.5.7</version>
7    </dependency>
8    <!--  mysql驱动包  -->
9    <dependency>
10        <groupId>mysql</groupId>
11        <artifactId>mysql-connector-java</artifactId>
12        <version>8.0.26</version>
13    </dependency>
14    <!-- spring -->
15    <dependency>
16        <groupId>org.springframework</groupId>
17        <artifactId>spring-context</artifactId>
18        <version>5.3.13</version>
19    </dependency>
20    <dependency>
21        <groupId>org.springframework</groupId>
22        <artifactId>spring-tx</artifactId>
23        <version>5.3.13</version>
24    </dependency>
25    <dependency>
26        <groupId>org.springframework</groupId>
27        <artifactId>spring-jdbc</artifactId>
28        <version>5.3.13</version>
29    </dependency>
30    <!-- MyBatisSpring的整合包,该包可以让Spring创建MyBatis的对象 -->
31    <dependency>
32        <groupId>org.mybatis</groupId>
33        <artifactId>mybatis-spring</artifactId>
34        <version>2.0.6</version>
35    </dependency>
36</dependencies>

2. Write configuration files

1. Write the database configuration file db.properties

1jdbc.driverClassName=com.mysql.jdbc.Driver
2jdbc.url=jdbc:mysql:///student
3jdbc.username=root
4jdbc.password=root

2. Create the MyBatis configuration file SqlMapConfig.xml. The data source and scanning interface are all managed by Spring and do not need to be set in the MyBatis configuration file.

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE configuration
3        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4        "http://mybatis.org/dtd/mybatis-3-config.dtd">
5<configuration>
6</configuration>

3. Create the Spring configuration file applicationContext.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:context="http://www.springframework.org/schema/context"
4       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5       xsi:schemaLocation="http://www.springframework.org/schema/beans
6         http://www.springframework.org/schema/beans/spring-beans.xsd
7         http://www.springframework.org/schema/context
8         http://www.springframework.org/schema/context/spring-context.xsd">
9    <!-- 包扫描 -->
10    <context:component-scan base-package="com.package"></context:component-scan>
11
12    <!-- 读取配置文件 -->
13    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
14    <!-- 创建druid数据源对象 -->
15    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
16        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
17        <property name="url" value="${jdbc.url}"></property>
18        <property name="username" value="${jdbc.username}"></property>
19        <property name="password" value="${jdbc.password}"></property>
20    </bean>
21
22    <!-- Spring创建封装过的SqlSessionFactory -->
23    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
24        <property name="dataSource" ref="dataSource"></property>
25    </bean>
26
27    <!-- Spring创建封装过的SqlSession -->
28    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
29        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
30    </bean>
31
32</beans>

3. Prepare the database and entity classes

prepare database

1CREATE DATABASE `student`;
2USE `student`;
3DROP TABLE IF EXISTS `student`;
4CREATE TABLE `student` (
5  `id` int(11) NOT NULL AUTO_INCREMENT,
6  `name` varchar(255) DEFAULT NULL,
7  `sex` varchar(10) DEFAULT NULL,
8  `address` varchar(255) DEFAULT NULL,
9  PRIMARY KEY (`id`)
10) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
11
12insert  into `student`(`id`,`name`,`sex`,`address`) values (1,'弋痕夕','男','炽天殿'),(2,'山鬼谣','男','阳天殿');

Prepare Entity Class

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String sex;
5    private String address;
6    
7    // 省略构造方法/getter/setter/tostring
8}

4. Write the persistence layer interface and service class

Write the persistence layer interface

1@Repository
2public interface StudentDao {
    
    
3    // 查询所有学生
4    @Select("select * from student")
5    List<Student> findAll();
6
7    // 添加学生
8    @Insert("insert into student values(null,#{name},#{sex},#{address})")
9    void add(Student student);
10}

Write service class

1@Service
2public class StudentService {
    
    
3    // SqlSession对象
4    @Autowired
5    private SqlSessionTemplate sqlSession;
6
7    // 使用SqlSession获取代理对象
8    public List<Student> findAllStudent(){
    
    
9        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
10        return studentDao.findAll();
11    }
12}

5. Spring integrates Junit for unit testing

Before unit testing, it was necessary to manually create the Spring container. Can Spring automatically create the container during the test?

1. Introduce Junit and Spring to integrate Junit dependencies

1<!-- junit,如果Spring5整合junit,则junit版本至少在4.12以上 -->
2<dependency>
3    <groupId>junit</groupId>
4    <artifactId>junit</artifactId>
5    <version>4.12</version>
6    <scope>test</scope>
7</dependency>
8<!-- spring整合测试模块 -->
9<dependency>
10    <groupId>org.springframework</groupId>
11    <artifactId>spring-test</artifactId>
12    <version>5.3.13</version>
13</dependency>

2. Write test class

1// JUnit使用Spring方式运行代码,即自动创建spring容器。
2@RunWith(SpringJUnit4ClassRunner.class)
3// 告知创建spring容器时读取哪个配置类或配置文件
4// 配置类写法:@ContextConfiguration(classes=配置类.class)
5@ContextConfiguration(locations="classpath:applicationContext.xml")
6public class StudentServiceTest {
    
    
7    @Autowired
8    private StudentService studentService;
9    
10    @Test
11    public void testFindAll(){
    
    
12        List<Student> allStudent = studentService.findAllStudent();
13        allStudent.forEach(System.out::println);
14    }
15}

Note: Using SqlSessionTemplate to create a proxy object still needs to register an interface or a mapping file.

1. Register the interface in the MyBatis configuration file

1<configuration>
2    <mappers>
3        <mapper class="com.package.dao.StudentDao"></mapper>
4    </mappers>
5</configuration>

2. Specify the MyBatis configuration file when creating sqlSessionFactory

1<!-- 创建Spring封装过的SqlSessionFactory -->
2<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
3    <property name="dataSource" ref="dataSource"></property>
4    <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
5</bean>

6. Automatically create proxy objects

Spring provides the MapperScannerConfigurer object, which can automatically scan the package to create a proxy object and put the proxy object into the container. At this time, there is no need to use SqlSession to manually create the proxy object.

1. Create a MapperScannerConfigurer object

1<!-- 该对象可以自动扫描持久层接口,并为接口创建代理对象 -->
2<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
3    <!-- 配置扫描的接口包 -->
4    <property name="basePackage" value="com.package.dao"></property>
5</bean>

2. The Service class can directly use the proxy object

1@Service
2public class StudentService {
    
    
3    // 直接注入代理对象
4    @Autowired
5    private StudentDao studentDao;
6  
7    // 直接使用代理对象
8    public void addStudent(Student student){
    
    
9        studentDao.add(student);
10    }
11}

3. Test

1@RunWith(SpringJUnit4ClassRunner.class)
2@ContextConfiguration(locations="classpath:applicationContext.xml")
3public class StudentServiceTest {
    
    
4    @Autowired
5    private StudentService studentService;
6    
7    @Test
8    public void testAdd(){
    
    
9        Student student = new Student(0, "嘟嘟", "女", "上海");
10        studentService.addStudent(student);
11    }
12}

6. Spring AOP

1. Introduction to AOP

The full name of AOP is Aspect Oriented Programming, that is, aspect-oriented programming. It is a technology to achieve unified maintenance of functions. It isolates various parts of business logic, so that developers can concentrate on core business when writing business logic, thereby improving development efficiency.

Function : On the basis of not modifying the source code, the existing methods are enhanced.
Implementation principle : dynamic proxy technology.
Advantages : Reduce repetitive code, improve development efficiency, and facilitate maintenance
Application scenarios : transaction processing, log management, authority control, exception handling, etc.

2. AOP related terms

In order to better understand AOP, you need to have some understanding of AOP-related terms

name illustrate
Joinpoint Refers to the point that can be intercepted. In Spring, only methods can be intercepted.
Pointcut Refers to which connection points to intercept, that is, the enhanced method.
Advice Refers to what to do after interception, that is, the method executed after the pointcut is intercepted.
Aspect pointcut + advice is called aspect
Target Proxied object
Proxy proxy object
Weaving The process of generating proxy objects

3. Introduction to AOP

AspectJ is an AOP framework based on the Java language. It is recommended to use AspectJ to implement AOP in the Spring framework.

Next, let's write an AOP entry case: each method of the dao layer can print a log after the end:

1. Introduce dependencies

1<!-- spring -->
2<dependency>
3    <groupId>org.springframework</groupId>
4    <artifactId>spring-context</artifactId>
5    <version>5.3.13</version>
6</dependency>
7<!-- AspectJ -->
8<dependency>
9    <groupId>org.aspectj</groupId>
10    <artifactId>aspectjweaver</artifactId>
11    <version>1.8.7</version>
12</dependency>
13<!--  junit  -->
14<dependency>
15    <groupId>junit</groupId>
16    <artifactId>junit</artifactId>
17    <version>4.12</version>
18    <scope>test</scope>
19</dependency>

2. Write the join point

1@Repository
2public class UserDao {
    
    
3    public void add(){
    
    
4        System.out.println("用户新增");
5    }
6    public void delete(){
    
    
7        System.out.println("用户删除");
8    }
9    public void update(){
    
    
10        System.out.println("用户修改");
11    }
12}

3. Write notification class

public class MyAspectJAdvice {
    
    
    // 后置通知
    public void myAfterReturning() {
    
    
        System.out.println("打印日志...");
   }
}

4. Configuration aspect

<?xml version="1.0" encoding="UTF-8"?>
<beans 
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/
spring-aop.xsd">
    <context:component-scan basepackage="com.package">
</context:component-scan>

   <!-- 通知对象 -->
    <bean id="myAspectJAdvice" 
class="com.itbaizhan.advice.MyAspectAdvice
"></bean>
    <!-- 配置AOP -->
    <aop:config>
        <!-- 配置切面 -->
        <aop:aspect ref="myAspectJAdvice">
            <!-- 配置切点 -->
            <aop:pointcut id="myPointcut" expression="execution(* com.package.dao.UserDao.*(..))"/>
            <!-- 配置通知 -->
            <aop:after-returning method="myAfterReturning" pointcutref="myPointcut"/>
       </aop:aspect>
    </aop:config>
</beans>

5. Test

public class UserDaoTest {
    
    
	@Test
	public void testAdd(){
    
    
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		UserDao userDao = (UserDao) ac.getBean("userDao");
		userDao.add();
	}
	@Test
	public void testDelete(){
    
    
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		UserDao userDao = (UserDao) ac.getBean("userDao");
		userDao.update();
	}
}

4. Notification Type

AOP has the following commonly used notification types:

notification type describe
advance notice Add functionality before method execution
post notification Add functionality after the normal execution of the method
Exception notification Add functionality after method throws exception
final notice This advice is executed regardless of whether the method throws an exception
surround notification Add functionality before and after method execution

1 Write the notification method

// 通知类
public class MyAspectAdvice {
    
    
    // 后置通知
    public void myAfterReturning(JoinPoint 
joinPoint) {
    
    
        System.out.println("切点方法名:" + 
joinPoint.getSignature().getName());
        System.out.println("目标对象:" + 
joinPoint.getTarget());
        System.out.println("打印日志" + 
joinPoint.getSignature().getName() + "方法
被执行了!");
   }
    // 前置通知
    public void myBefore() {
    
    
        System.out.println("前置通知...");
   }
    // 异常通知
    public void myAfterThrowing(Exception 
ex) {
    
    
        System.out.println("异常通知...");
         System.err.println(ex.getMessage());
   }
    // 最终通知
    public void myAfter() {
    
    
        System.out.println("最终通知");
   }
    // 环绕通知
    public Object 
myAround(ProceedingJoinPoint 
proceedingJoinPoint) throws Throwable {
    
    
        System.out.println("环绕前");
        Object obj = 
proceedingJoinPoint.proceed(); // 执行方法
        System.out.println("环绕后");
        return obj;
   }
}

2 configuration aspect

<!-- 配置AOP -->
<aop:config>
    <!-- 配置切面 -->
    <aop:aspect ref="myAspectJAdvice">
        <!-- 配置切点 -->
        <aop:pointcut id="myPointcut" 
expression="execution(* 
com.itbaizhan.dao.UserDao.*(..))"/>
        <!-- 前置通知 -->
        <aop:before method="myBefore" 
pointcut-ref="myPointcut"></aop:before>
        <!-- 后置通知 -->
        <aop:after-returning 
method="myAfterReturning" pointcutref="myPointcut"/>

       <!-- 异常通知 -->
        <aop:after-throwing 
method="myAfterThrowing" pointcutref="myPointcut"
throwing="ex"/>
        <!-- 最终通知 -->
        <aop:after method="myAfter" 
pointcut-ref="myPointcut"></aop:after>
        <!-- 环绕通知 -->
        <aop:around method="myAround" 
pointcut-ref="myPointcut"></aop:around>
    </aop:aspect>
</aop:config>

5. Pointcut expression

To use AspectJ, you need to use a pointcut expression to configure the pointcut location, which is written as follows:

Standard writing: access modifier return value package name. class name. method name (parameter list)

Access modifiers can be omitted.

The return value is used *to represent any type.

Use the package name *to indicate any package, write multiple multi-level package structures *, use to *..indicate any package structure

Both class names and method names can be used to *achieve wildcards.

Parameter list
Basic data type Direct write type
Reference type write 包名.类名
*means match a parameter of any type
..means match any number of parameters of any type

All wildcards:* *..*.*(..)

6. Multi-facet configuration

insert image description here
We can configure multiple notifications for the cut point to form multiple aspects. For example, we hope that each method of the dao layer can print logs and send emails after the end:

1. Write a notification to send an email:

1public class MyAspectJAdvice2 {
    
    
2    // 后置通知
3    public void myAfterReturning(JoinPoint joinPoint) {
    
    
4        System.out.println("发送邮件");
5    }
6}

2. Configuration aspect:

1<!-- 通知对象 -->
2<bean id="myAspectJAdvice" class="com.package.advice.MyAspectAdvice"></bean>
3<bean id="myAspectJAdvice2" class="com.package.advice.MyAspectAdvice2"></bean>
4
5<!-- 配置AOP -->
6<aop:config>
7    <!-- 配置切面 -->
8    <aop:aspect ref="myAspectJAdvice">
9        <!-- 配置切点 -->
10        <aop:pointcut id="myPointcut" expression="execution(* *..*.*(..))"/>
11        <!-- 后置通知 -->
12        <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
13    </aop:aspect>
14    
15    <aop:aspect ref="myAspectJAdvice2">
16        <aop:pointcut id="myPointcut2" expression="execution(* com.package.dao.UserDao.*(..))"/>
17        <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut2"/>
18    </aop:aspect>
19</aop:config>

7. Annotate configuration AOP

Spring can use annotations instead of configuration files to configure aspects:

1. Enable AOP annotation support in xml

1<!-- 开启注解配置Aop -->
2<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2. Add annotations above the notification class@Aspect

3. Add annotations above the notification method@Before/@AfterReturning/@AfterThrowing/@After/@Around

1@Aspect
2@Component
3public class MyAspectAdvice {
    
    
4    // 后置通知
5    @AfterReturning("execution(* com.package.dao.UserDao.*(..))")
6    public void myAfterReturning(JoinPoint joinPoint) {
    
    
7        System.out.println("切点方法名:" + joinPoint.getSignature().getName());
8        System.out.println("目标对象:" + joinPoint.getTarget());
9        System.out.println("打印日志" + joinPoint.getSignature().getName() + "方法被执行了!");
10    }
11
12    // 前置通知
13    @Before("execution(* com.package.dao.UserDao.*(..))")
14    public void myBefore() {
    
    
15        System.out.println("前置通知...");
16    }
17
18    // 异常通知
19    @AfterThrowing(value = "execution(* com.package.dao.UserDao.*(..))",throwing = "ex")
20    public void myAfterThrowing(Exception ex) {
    
    
21        System.out.println("异常通知...");
22        System.err.println(ex.getMessage());
23    }
24
25    // 最终通知
26    @After("execution(* com.package.dao.UserDao.*(..))")
27    public void myAfter() {
    
    
28        System.out.println("最终通知");
29    }
30
31    // 环绕通知
32    @Around("execution(* com.package.dao.UserDao.*(..))")
33    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    
    
34        System.out.println("环绕前");
35        Object obj = proceedingJoinPoint.proceed(); // 执行方法
36        System.out.println("环绕后");
37        return obj;
38    }
39}

4. Test:

1@Test
2public void testAdd2(){
    
    
3    ApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
4    UserDao userDao = (UserDao) ac.getBean("userDao");
5    userDao.update();
6}

How to uniformly configure pointcuts for all methods under a class:

1. Add a method configuration pointcut in the notification class

1@Pointcut("execution(* com.package.dao.UserDao.*(..))")
2public void pointCut(){
    
    }

2. Use the defined pointcut on the notification method

1@Before("pointCut()")
2public void myBefore(JoinPoint joinPoint) {
    
    
3    System.out.println("前置通知...");
4}
5
6@AfterReturning("pointCut()")
7public void myAfterReturning(JoinPoint joinPoint) {
    
    
8    System.out.println("后置通知...");
9}

How does the configuration class replace the AOP annotation support in xml?

@EnableAspectJAutoProxyJust add it above the configuration class

1@Configuration
2@ComponentScan("com.package")
3@EnableAspectJAutoProxy
4public class SpringConfig {
    
    
5
6}

8. Native Spring implements AOP

In addition to AspectJ, Spring supports AOP natively.

1. Introduce dependencies

1<!-- AOP -->
2<dependency>
3    <groupId>org.springframework</groupId>
4    <artifactId>spring-aop</artifactId>
5    <version>5.3.13</version>
6</dependency>

2. Write notification class

1// Spring原生Aop的通知类
2public class SpringAop implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice, MethodInterceptor {
    
    
3    /**
4     * 前置通知
5     * @param method 目标方法
6     * @param args 目标方法的参数列表
7     * @param target 目标对象
8     * @throws Throwable
9     */
10    @Override
11    public void before(Method method, Object[] args, Object target) throws Throwable {
    
    
12        System.out.println("前置通知");
13    }
14
15    /**
16     * 后置通知
17     * @param returnValue 目标方法的返回值
18     * @param method 目标方法
19     * @param args 目标方法的参数列表
20     * @param target 目标对象
21     * @throws Throwable
22     */
23    @Override
24    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    
    
25        System.out.println("后置通知");
26    }
27
28    /**
29     * 环绕通知
30     * @param invocation 目标方法
31     * @return
32     * @throws Throwable
33     */
34    @Override
35    public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
36        System.out.println("环绕前");
37        Object proceed = invocation.proceed();
38        System.out.println("环绕后");
39        return proceed;
40    }
41
42    /**
43     * 异常通知
44     * @param ex 异常对象
45     */
46    public void afterThrowing(Exception ex){
    
    
47        System.out.println("发生异常了!");
48    }
49}

When Spring natively implements AOP, only four notification types are supported:

notification type implement the interface
advance notice MethodBeforeAdvice
post notification AfterReturningAdvice
Exception notification ThrowsAdvice
surround notification MethodInterceptor

3. Write configuration class

1<!-- 通知对象 -->
2<bean id="springAop" class="com.package.advice.SpringAop"></bean>
3
4<!-- 配置代理对象 -->
5<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
6    <!-- 配置目标对象 -->
7    <property name="target" ref="userDao"></property>
8    <!-- 配置通知 -->
9    <property name="interceptorNames">
10        <list>
11            <value>springAop</value>
12        </list>
13    </property>
14    <!-- 代理对象的生成方式  true:使用CGLib false:使用原生JDK生成-->
15    <property name="proxyTargetClass" value="true"></property>
16</bean>

4. Write test class

1public class UserDaoTest2 {
    
    
2    @Test
3    public void testAdd(){
    
    
4        ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml");
5        UserDao userDao = (UserDao) ac.getBean("userDaoProxy"); // 获取的是代理对象
6        userDao.update();
7    }
8}

9. SchemaBased implements AOP

The SchemaBased (basic mode) configuration method refers to using the Spring native method to define notifications, and using the AspectJ framework to configure aspects.

1. Write notification class

1public class SpringAop implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice, MethodInterceptor {
    
    
2    /**
3     * 前置通知
4     * @param method 目标方法
5     * @param args 目标方法的参数列表
6     * @param target 目标对象
7     * @throws Throwable
8     */
9    @Override
10    public void before(Method method, Object[] args, Object target) throws Throwable {
    
    
11        System.out.println("前置通知");
12    }
13
14    /**
15     * 后置通知
16     * @param returnValue 目标方法的返回值
17     * @param method 目标方法
18     * @param args 目标方法的参数列表
19     * @param target 目标对象
20     * @throws Throwable
21     */
22    @Override
23    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    
    
24        System.out.println("后置通知");
25    }
26
27    /**
28     * 环绕通知
29     * @param invocation 目标方法
30     * @return
31     * @throws Throwable
32     */
33    @Override
34    public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
35        System.out.println("环绕前");
36        Object proceed = invocation.proceed();
37        System.out.println("环绕后");
38        return proceed;
39    }
40
41    /**
42     * 异常通知
43     * @param ex 异常对象
44     */
45    public void afterThrowing(Exception ex){
    
    
46        System.out.println("发生异常了!");
47    }
48}

2. Configuration aspect

1<!-- 通知对象 -->
2<bean id="springAop2" class="com.package.aop.SpringAop2"/>
3
4<!-- 配置切面 -->
5<aop:config>
6    <!-- 配置切点-->
7    <aop:pointcut id="myPointcut" expression="execution(* com.package.dao.UserDao.*(..))"/>
8    <!-- 配置切面:advice-ref:通知对象 pointcut-ref:切点 -->
9    <aop:advisor advice-ref="springAop2" pointcut-ref="myPointcut"/>
10</aop:config>

3. Test

1@Test
2public void t6(){
    
    
3    ApplicationContext ac = new ClassPathXmlApplicationContext("aop3.xml");
4    UserDao userDao = (UserDao) ac.getBean("userDao");
5    userDao.add();
6}

Seven, Spring affairs

1. Business Introduction

Transactions: Indivisible atomic operations. That is, a series of operations either succeed at the same time or fail at the same time.

During the development process, transaction management is generally in the service layer, and the database may be operated multiple times in the service layer, and these operations are inseparable. Otherwise, when the program reports an error, data exceptions may occur.

For example: when Zhang San transfers money to Li Si, the database needs to be operated twice: Zhang San's deposit decreases and Li Si's deposit increases. If an exception occurs between these two database operations, data errors will result.

1. Prepare the database

1CREATE DATABASE `spring` ;
2USE `spring`;
3DROP TABLE IF EXISTS `account`;
4
5CREATE TABLE `account` (
6  `id` int(11) NOT NULL AUTO_INCREMENT,
7  `username` varchar(255) DEFAULT NULL,
8  `balance` double DEFAULT NULL,
9  PRIMARY KEY (`id`)
10) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
11
12insert  into `account`(`id`,`username`,`balance`) values (1,'猪猪侠',1000),(2,'开心超人',1000);

2. Create a maven project and introduce dependencies

1<dependencies>
2    <!--  mybatis  -->
3    <dependency>
4        <groupId>org.mybatis</groupId>
5        <artifactId>mybatis</artifactId>
6        <version>3.5.7</version>
7    </dependency>
8    <!--  mysql驱动包  -->
9    <dependency>
10        <groupId>mysql</groupId>
11        <artifactId>mysql-connector-java</artifactId>
12        <version>8.0.26</version>
13    </dependency>
14    <!--  druid连接池  -->
15    <dependency>
16        <groupId>com.alibaba</groupId>
17        <artifactId>druid</artifactId>
18        <version>1.2.8</version>
19    </dependency>
20    <!-- spring -->
21    <dependency>
22        <groupId>org.springframework</groupId>
23        <artifactId>spring-context</artifactId>
24        <version>5.3.13</version>
25    </dependency>
26    <dependency>
27        <groupId>org.springframework</groupId>
28        <artifactId>spring-tx</artifactId>
29        <version>5.3.13</version>
30    </dependency>
31    <dependency>
32        <groupId>org.springframework</groupId>
33        <artifactId>spring-jdbc</artifactId>
34        <version>5.3.13</version>
35    </dependency>
36    <!-- MyBatisSpring的整合包,该包可以让Spring创建MyBatis的对象 -->
37    <dependency>
38        <groupId>org.mybatis</groupId>
39        <artifactId>mybatis-spring</artifactId>
40        <version>2.0.6</version>
41    </dependency>
42
43    <!-- junit,如果Spring5整合junit,则junit版本至少在4.12以上 -->
44    <dependency>
45        <groupId>junit</groupId>
46        <artifactId>junit</artifactId>
47        <version>4.12</version>
48        <scope>test</scope>
49    </dependency>
50    <!-- spring整合测试模块 -->
51    <dependency>
52        <groupId>org.springframework</groupId>
53        <artifactId>spring-test</artifactId>
54        <version>5.3.13</version>
55        <scope>test</scope>
56    </dependency>
57</dependencies>

3. Create a configuration file

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:context="http://www.springframework.org/schema/context"
4       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5       xsi:schemaLocation="http://www.springframework.org/schema/beans
6         http://www.springframework.org/schema/beans/spring-beans.xsd
7         http://www.springframework.org/schema/context
8         http://www.springframework.org/schema/context/spring-context.xsd">
9    <!-- 包扫描 -->
10    <context:component-scan base-package="com.package"></context:component-scan>
11    <!-- 创建druid数据源对象 -->
12    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
13        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
14        <property name="url" value="jdbc:mysql:///spring"></property>
15        <property name="username" value="root"></property>
16        <property name="password" value="root"></property>
17    </bean>
18
19    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
20        <property name="dataSource" ref="dataSource"></property>
21    </bean>
22
23    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
24        <property name="basePackage" value="com.package.dao"></property>
25    </bean>
26</beans>

4. Write Java code

1// 账户
2public class Account {
    
    
3    private int id; // 账号
4    private String username; // 用户名
5    private double balance; // 余额
6    
7    // 省略getter/setter/tostring/构造方法
8}
9
10@Repository
11public interface AccountDao {
    
    
12    // 根据id查找用户
13    @Select("select * from account where id = #{id}")
14    Account findById(int id);
15
16    // 修改用户
17    @Update("update account set balance = #{balance} where id = #{id}")
18    void update(Account account);
19}
20
21@Service
22public class AccountService {
    
    
23    @Autowired
24    private AccountDao accountDao;
25
26    /**
27     * 转账
28     * @param id1 转出人id
29     * @param id2 转入人id
30     * @param price 金额
31     */
32    public void transfer(int id1, int id2, double price) {
    
    
33        // 转出人减少余额
34        Account account1 = accountDao.findById(id1);
35        account1.setBalance(account1.getBalance()-price);
36        accountDao.update(account1);
37
38        int i = 1/0; // 模拟程序出错
39
40        // 转入人增加余额
41        Account account2 = accountDao.findById(id2);
42        account2.setBalance(account2.getBalance()+price);
43        accountDao.update(account2);
44    }
45}

5. Test transfer

1@RunWith(SpringJUnit4ClassRunner.class)
2@ContextConfiguration(locations="classpath:applicationContext.xml")
3public class AccountServiceTest {
    
    
4    @Autowired
5    private AccountService accountService;
6
7    @Test
8    public void testTransfer(){
    
    
9        accountService.transfer(1,2,500);
10    }
11}

At this time, if there is no transaction management, Zhang San's balance will decrease, but Li Si's balance will not increase. Therefore, transaction processing is located in the business layer, that is, a service method cannot be separated.

2. Spring transaction management scheme

Manually adding transactions at the service layer can solve this problem:

1@Autowired
2private SqlSessionTemplate sqlSession;
3
4public void transfer(int id1, int id2, double price) {
    
    
5    try{
    
    
6        // account1修改余额
7        Account account1 = accountDao.findById(id1);
8        account1.setBalance(account1.getBalance()-price);
9        accountDao.update(account1);
10
11        int i = 1/0; // 模拟转账出错
12
13        // account2修改余额
14        Account account2 = accountDao.findById(id2);
15        account2.setBalance(account2.getBalance()+price);
16        accountDao.update(account2);  
17        sqlSession.commit();
18    }catch(Exception ex){
    
    
19        sqlSession.rollback();
20    }
21}

But manual commit and rollback of transactions is not allowed under Spring management. At this point we need to use Spring's transaction management solution, which provides two transaction management solutions in the Spring framework:

1. Programmatic transactions: realize transaction management by writing code.
2. Declarative transaction: Realize transaction management based on AOP technology.

Spring's declarative transaction management adopts AOP technology at the bottom layer. Its biggest advantage is that it does not need to manage transactions through programming. It only needs to declare relevant rules in the configuration file to apply transaction rules to business logic.

Use AOP technology to add the following notification to the service method:
insert image description here

3. Spring transaction manager

Spring relies on the transaction manager for transaction management. The transaction manager is a notification class. We set the cut point for the notification class as a service layer method to complete automatic transaction management. Since different technologies operate databases, the methods for performing transaction operations are different. For example: JDBC submits transactions connection.commit(), MyBatis submits transactions sqlSession.commit(), so Spring provides multiple transaction managers.

transaction manager name effect
org.springframework.jdbc.datasource.DataSourceTransactionManager A transaction manager for JDBC technology. Works with JDBC and MyBatis.
org.springframework.orm.hibernate3.HibernateTransactionManager
org.springframework.orm.jpa.JpaTransactionManager The transaction manager provided for JPA technology. Applicable to JPA technology.
org.springframework.transaction.jta.JtaTransactionManager Spans multiple transaction management sources. It is suitable for implementing transaction control in two or more different data sources.

We use MyBatis to operate the database, and then use DataSourceTransactionManager for transaction management.

1. Introduce dependencies

1<!-- 事务管理 -->
2<dependency>
3    <groupId>org.springframework</groupId>
4    <artifactId>spring-tx</artifactId>
5    <version>5.3.13</version>
6</dependency>
7<!-- AspectJ -->
8<dependency>
9    <groupId>org.aspectj</groupId>
10    <artifactId>aspectjweaver</artifactId>
11    <version>1.8.7</version>
12</dependency>

2. Introduce constraints in the configuration file

1xmlns:aop="http://www.springframework.org/schema/aop"
2xmlns:tx="http://www.springframework.org/schema/tx"
3
4http://www.springframework.org/schema/aop
5http://www.springframework.org/schema/aop/spring-aop.xsd
6http://www.springframework.org/schema/tx
7http://www.springframework.org/schema/tx/spring-tx.xsd

3. Perform transaction configuration

1<!-- 事务管理器  -->
2<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
3    <property name="dataSource" ref="dataSource"></property>
4</bean>
5
6<!-- 进行事务相关配置 -->
7<tx:advice id = "txAdvice">
8    <tx:attributes>
9        <tx:method name="*"/>
10    </tx:attributes>
11</tx:advice>
12
13<!-- 配置切面 -->
14<aop:config>
15    <!-- 配置切点 -->
16    <aop:pointcut id="pointcut" expression="execution(* com.package.service.*.*(..))"/>
17    <!-- 配置通知 -->
18    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
19</aop:config>

4. Transaction control API

Spring's transaction control function is provided by three interfaces. These three interfaces are implemented by Spring. We rarely use them in development. We only need to understand their functions:

The PlatformTransactionManager interface
PlatformTransactionManager is a transaction manager interface provided by Spring, and all transaction managers implement this interface. This interface provides three transaction operation methods:

TransactionStatus getTransaction(TransactionDefinition definition): Get transaction status information.
void commit(TransactionStatus status):transaction commit
void rollback(TransactionStatus status):transaction rollback

The TransactionDefinition interface
TransactionDefinition is the definition information object of the transaction, which has the following methods:

String getName(): Get the transaction object name.
int getIsolationLevel(): Gets the isolation level of the transaction.
int getPropagationBehavior(): Get the propagation behavior of the transaction.
int getTimeout(): Get the timeout of the transaction.
boolean isReadOnly(): Get whether the transaction is read-only.

The TransactionStatus interface
TransactionStatus is the status interface of the transaction, which describes the status information of the transaction at a certain point in time. It has the following methods:

void flush()Refresh transaction
boolean hasSavepoint() Get whether there is a savepoint
boolean isCompleted() Get whether the transaction is completed
boolean isNewTransaction() Get whether it is a new transaction
boolean isRollbackOnly() Get whether to rollback
void setRollbackOnly() Set transaction rollback

<tx:advice>Transaction-related configurations can be made in :

1<tx:advice id="txAdvice">
2    <tx:attributes>
3        <tx:method name="*"/>
4        <tx:method name="find*" read-only="true"/>
5    </tx:attributes>
6</tx:advice>

<tx:method>properties in:

name: Specifies the method of configuration. *Represents all methods, find*representing all methods starting with find.
read-only: Whether it is a read-only transaction. There is no data modification in the read-only transaction. The database will provide some optimization methods for the read-only transaction, which will improve the performance to a certain extent. It is recommended to enable the read-only transaction in the query.
timeout: Specify the timeout period, if all operations cannot be completed within the limited time, an exception will be thrown. The default is never timeout
rollback-for: Specifies that an abnormal transaction is rolled back, and other exceptions are not rolled back. By default all exceptions are rolled back.
no-rollback-for: Specifies that an exception is not rolled back, and other exceptions are rolled back. By default all exceptions are rolled back.
propagation: transaction propagation behavior
isolation: transaction isolation level

5. Transaction propagation behavior

Transaction propagation behavior refers to how transactions are propagated among methods when multiple methods containing transactions call each other.

If other service methods are called in the method of the service layer, assuming that the transaction must be started every time the service method is executed, then there is no guarantee that the outer method and the inner method are in the same transaction.

1// method1的所有方法在同一个事务中
2public void method1(){
    
    
3    // 此时会开启一个新事务,这就无法保证method1()中所有的代码是在同一个事务中
4    method2();
5    System.out.println("method1");
6}
7
8public void method2(){
    
    
9    System.out.println("method2");
10}

The propagation feature of the transaction is to solve this problem. Spring helps us put the outer method and the inner method into the same transaction.

communication behavior introduce
REQUIRED default. Support the current transaction, if there is no current transaction, create a new transaction. This is the most common choice.
SUPPORTS Support the current transaction, if there is no current transaction, it will be executed in a non-transactional manner.
MANDATORY Support the current transaction, if there is no current transaction, an exception will be thrown.
REQUIRES_NEW Create a new transaction, if there is a current transaction, suspend the current transaction.
NOT_SUPPORTED Perform operations in a non-transactional manner, and suspend the current transaction if there is a current transaction.
NEVER Executes non-transactionally, throwing an exception if a transaction currently exists.
NESTED Must be executed in a transaction state, if there is no transaction, create a new transaction, if there is a current transaction, create a nested transaction

6. Transaction isolation level

The transaction isolation level reflects the processing attitude when the transaction is submitted for concurrent access. The higher the isolation level, the lower the possibility of data problems, but the lower the efficiency.

isolation level dirty read non-repeatable read Phantom reading
READ_UNCOMMITED (read uncommitted content) Yes Yes Yes
READ_COMMITED (read commit content) No Yes Yes
REPEATABLE_READ (repeated read) No No Yes
SERIALIZABLE (serializable) No No No

If set to DEFAULT the isolation level of the database will be used.

SqlServer, Oracle default transaction isolation level is READ_COMMITED
Mysql default isolation level is REPEATABLE_READ

7. Annotation configuration declarative transaction

Spring supports the configuration of declarative transactions using annotations. The usage is as follows:

1. Registration transaction annotation driver

1<!-- 注册事务注解驱动 -->
2<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

2. Add @Transactional to the method or class that needs transaction support

1@Service
2// 作用于类上时,该类的所有public方法将都具有该类型的事务属性
3@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
4public class AccountService {
    
    
5    @Autowired
6    private AccountDao accountDao;
7
8    /**
9     * 转账
10     * @param id1 转出人id
11     * @param id2 转入人id
12     * @param price 金额
13     */
14    // 作用于方法上时,该方法将都具有该类型的事务属性
15    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
16    public void transfer(int id1, int id2, double price) {
    
    
17        // account1修改余额
18        Account account1 = accountDao.findById(id1);
19        account1.setBalance(account1.getBalance()-price);
20        accountDao.update(account1);
21
22        int i = 1/0; // 模拟转账出错
23
24        // account2修改余额
25        Account account2 = accountDao.findById(id2);
26        account2.setBalance(account2.getBalance()+price);
27        accountDao.update(account2);
28    }
29}

3. The configuration class replaces the annotation transaction support in xml: write @EnableTranscationManagement above the configuration class

1@Configuration
2@ComponentScan("com.package")
3@EnableTransactionManagement
4public class SpringConfig {
    
    
5
6    @Bean
7    public DataSource getDataSource(){
    
    
8        DruidDataSource druidDataSource = new DruidDataSource();
9        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
10        druidDataSource.setUrl("jdbc:mysql:///spring");
11        druidDataSource.setUsername("root");
12        druidDataSource.setPassword("root");
13        return druidDataSource;
14    }
15
16    @Bean
17    public SqlSessionFactoryBean getSqlSession(DataSource dataSource){
    
    
18        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
19        sqlSessionFactoryBean.setDataSource(dataSource);
20        return sqlSessionFactoryBean;
21    }
22
23    @Bean
24    public MapperScannerConfigurer getMapperScanner(){
    
    
25        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
26        mapperScannerConfigurer.setBasePackage("com.package.dao");
27        return mapperScannerConfigurer;
28    }
29
30    @Bean
31    public DataSourceTransactionManager getTransactionManager(DataSource dataSource){
    
    
32        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
33        dataSourceTransactionManager.setDataSource(dataSource);
34        return dataSourceTransactionManager;
35    }
36}

Guess you like

Origin blog.csdn.net/TIpotencial/article/details/123898868