Detailed Explanation of Spring Framework (Spring Framework)

overview

Spring System Overview

  • Spring is a full-stack lightweight Java open source framework that emerged in 2003. It was created by Rod Johnson. Using Spring can make Java programming faster, easier and safer.
  • Spring is an ecosystem , or a super glue platform. Common Spring projects include: Spring Boot, Spring Framework, Spring Data, Spring Cloud, Spring Cloud Data Flow, Spring Security, Spring GraphQL, Spring Session and Spring Web Services, etc.
  • Spring provides many enterprise-level application technologies such as Spring MVC for the presentation layer, Spring JDBC for the persistence layer, and transaction management for the business layer. Spring can also integrate numerous third-party frameworks and class libraries in the open source world, and has gradually become the most widely used open source framework for Java EE enterprise applications.
  • Spring is not equivalent to Spring Framework (Spring Framework), which is a common misconception

Spring Framework (Spring Framework)

overview

  • The Spring framework, that is, the Spring Framework framework , is one of the important projects of the Spring ecology, and it is also the foundation and core of other Spring family buckets (SpringMVC, SpringBoot, SpringCloud, SpringData, etc.)
  • The Spring framework is divided into modules, and the application can choose the modules it needs. The core of the Spring framework is the Core Container (core container) module, including the configuration model and dependency injection mechanism
  • The Spring Framework provides fundamental support for different application architectures, including messaging, transactional data and persistence, and Web
  • The Spring Framework also includes the Servlet-based Spring MVC web framework, and the parallel Spring WebFlux reactive web framework
  • The Spring framework is a layered JavaSE/EE one-stop lightweight open source framework, with IOC (Inversion of Control) and AOP (Aspect-Oriented Programming) as the core

Features of the Spring Framework

  • Convenient decoupling and simplified development: all object creation and dependency maintenance are handed over to Spring management
  • Convenient integration of various excellent frameworks: Spring provides direct support for various excellent frameworks (Struts2, Hibernate, MyBatis)
  • Reduce the difficulty of using Java EE API: Provides encapsulation for some APIs (JDBC, JavaMail, remote call) in JAVA EE development
  • Convenient program testing: support JUnit4, you can easily test Spring programs through annotations
  • AOP becomes support: aspect-oriented programming, which can conveniently implement functions such as permission interception and operation monitoring of programs
  • Declarative transaction: transaction management can be completed through configuration without programming

Architecture and Module Description of the Spring Framework

insert image description here

The main modules of the Spring framework

  • Core Container (core container)

    It is the foundation of other modules and consists of Beans module, Core core module, Context context module and SpEL expression language module

    • Core (spring-core): encapsulates the underlying part of the Spring framework, including resource access, type conversion, and the basic core tool classes of the Spring framework

      Other Spring components must use the classes in this package, which are the basic core of other components, and you can also use these tool classes in your own application system

      • External dependencies: Commons Logging, (Log4J)
      • jar包:org.springframework spring-core 4.3.7.RELEASE
    • Beans (spring-beans): Provides the basic part of the framework, including access configuration files, inversion of control (IOC) and dependency injection (DI)

      • External dependencies: spring-core
      • jar包:org.springframework spring-beans 4.3.7.RELEASE
    • SpEL (spring-expression): Provides powerful expression language support for querying and processing object graphs at runtime. The language supports setting and getting property values; property assignment, method invocation, accessing the contents of arrays, collections and indexers, logical and arithmetic operations, named variables, and retrieval from Spring's IOC container's moniker. It also supports list selection and projection as well as common list aggregations

      • jar包:org.springframework spring-expression 4.3.7.RELEASE
    • Context (spring-context): Context module, based on Core and Beans modules, integrates Beans modules and adds resource binding, data validation, internationalization, Java EE support, container life cycle, event propagation, etc.

      Provides a number of extensions to the Spring core. You can find all the classes required when using the Spring ApplicationContext feature, all the classes required by JDNI, instrumentation components, and related classes related to Validation.

      • External dependencies: spring-core, spring-beans, spring-expression, spring-aop
      • jar包:org.springframework spring-context 4.3.7.RELEASE

    dependencies:

    insert image description here

  • Data Access/Integration (data access and integration)

    Contains modules: JDBC, ORM, OXM, JMS, Transaction

    • JDBC (spring-jdbc): Contains all classes that encapsulate Spring's access to JDBC data

      • jar包:org.springframework spring-jdbc 4.3.7.RELEASE
    • ORM (spring-orm): Provides an API integrated with the "object-relational" mapping framework, including JPA, JDO, Hibernate, MyBatis, etc.

    • OXM (spring-oxm): Provides an abstract layer implementation of Object/XML mapping, such as JAXB, Castor, XMLBean, JiBX, XStream

      Map java objects to XML data, or map XML data to java objects

    • JMS (spring-jms): java message service, which provides a set of "message producer, message consumer" templates, JMS is used to send messages between two applications or in a distributed system for asynchronous communication

    • Transaction (spring-tx): transaction control, consistent declarative and programmatic transaction management support for JDBC, Hibernate, JDO, JPA, Beans, etc.

      • jar包:org.springframework spring-tx 4.3.7.RELEASE

    dependencies:

    insert image description here

  • Web

    Includes modules: Web, servlet, websocket, portlet

    • Web (spring-web): Provides basic web integration features, such as: multi-file upload, IOC container initialization using Servlet listener, and web application context

      Contains the core classes required when using the Spring framework when developing web applications, including classes that automatically load Web ApplicationContext features, Struts and JSF integration classes, file upload support classes, Filter classes, and a large number of tool auxiliary classes

      • jar包:org.springframework spring-web 4.3.7.RELEASE
    • servlet (spring-webmvc): Provides SpringMVC Web framework implementation. SpringMVC provides annotation-based request resource injection, simpler data binding, data validation, etc., and a very simple set of JSP tags

      Contains all classes related to the Spring MVC framework, including framework Servlets, Web MVC framework, controller and view support

      If the application uses a standalone MVC framework, no classes in this JAR file are required

      • jar包:org.springframework spring-webmvc 4.3.7.RELEASE
    • WebSocket: Provides a simple interface, users only need to implement the interface to quickly build a websocket server, so as to achieve two-way communication

    • Portlet (spring-webmvc-portlet): Provides MVC implementation in the Portlet environment

    dependencies:

    insert image description here

  • AOP、aspects、spring-instrument 、messaging

    The aop part contains 4 modules

    • AOP (spring-aop): Provides aspect-oriented programming, provides technologies such as logging, access control, performance statistics and other common functions and business logic separation technology, and can dynamically add these functions to the required code

      • jar包:org.springframework spring-aop 4.3.7.RELEASE
    • Aspects (spring-aspects): Provides integration with AspectJ, a powerful and mature aspect-oriented programming framework

      In order to easily integrate aspect-oriented functions into IDEs, such as Eclipse AJDT

      • jar包:org.springframework spring-aspects 4.3.7.RELEASE
    • InStrumentation (spring-instrument): detection, providing support for class tools and implementation of class loaders

    • Messaging: Provides support for messaging architectures and protocols

    dependencies:

    insert image description here

  • Test: Spring supports the Junit and TestNG testing frameworks, and also provides some additional Spring-based testing functions.


The API system of the Spring framework

The API system of the Spring Framework is extremely large, and only BeanFactory and ApplicationContext are introduced for the time being:

  • BeanFactory

    • BeanFactory is the "heart" of Spring, the core interface of the IOC container, which defines the basic functions of IOC
    • Spring uses it to configure documents, manage bean loading, instantiate and maintain dependencies between beans, and be responsible for the bean lifecycle
  • ApplicationContext

    • ApplicationContext is derived from BeanFactory, which can be compared to the body of Spring
    • ApplicationContext adds many functions on the basis of BeanFactory:
      • Support aop function and web application
      • MessageSource, providing internationalized message access
      • Through configuration, many functions that can only be realized by coding in BeanFactory are realized
    • Common implementation classes of ApplicationContext:
      • ClassPathXmlApplicationContext: read configuration files from the classpath directory
      • FileSystemXmlApplicationContext: read configuration files from the file system or url
      • AnnotationConfigApplicationContext: read annotations. When using annotations to configure container objects, you need to use this class to create spring
        containers

The difference between BeanFactory and ApplicationContext:

  • The beanFactory is mainly for the infrastructure of the Spring framework, that is, for the internal calls of spring itself

    Applicationcontext is mainly for Spring users

  • BeanFactroy loads and instantiates a Bean when it is used for the first time (calling the getBean() method)

    ApplicationContext creates and loads all beans at one time when the container starts

insert image description here


Spring Boot framework overview

  • Spring Boot is also an extremely important project in the Spring ecosystem. Spring Boot is an extension of the Spring Framework. It can also be said that it is a framework that serves the framework. It is designed to simplify the initial construction and development process of new Spring applications.

  • The service scope of Spring Boot is to simplify the configuration file, which eliminates the XML configuration required to set up the Spring application, that is, to automatically configure the Spring application as much as possible

  • Spring Boot embeds Tomcat, Jetty or Undertow directly (no need to deploy WAR files), and provides production-ready features such as metrics, health checks, externalized configuration, and more, paving the way for faster and more efficient application development


IOC (Inversion of Control)

IOC overview, IOC container working principle

IOC (Inversion of Control) is a design idea, the purpose is to guide the design of a more loosely coupled program:

  • Control: refers to the object control right, which can be simply understood as the control authority of the object in java (such as the creation, destruction and other permissions of the object)
  • Inversion: refers to the inversion of the control of the object from the original programmer's active control in the class to the control of the Spring container
  • Main function: Decoupling

The Spring IOC container is an implementation of the IOC idea:

  • The creation of objects is managed by the Spring framework, and when objects are needed, they can be obtained from the Spring IOC container
  • The underlying principle: reflection

Spring's IOC container works:

  1. When Spring's IOC container loads, it reads many bean configurations in the configuration file

  2. Find the corresponding Class bytecode file according to the value of the bean class

  3. Through reflection technology, create objects one by one

  4. The created object will be stored in an internal Map structure, waiting to be used

  5. When you need to use specific objects, you don't need to create them manually, but directly from Spring's IOC container


Getting started with Spring IOC (xml)

Case: Get objects through the built-in container in Spring

Steps:

  • Create project import dependencies
  • Configuration interface and implementation class
  • Write Spring configuration files
  • Test: get object from container

Create project import dependencies

    <dependencies>
        <!--spring的坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

Create Dao interface and implementation class (omitted)

Create a Spring configuration file

  • The spring configuration file convention is commonly known as: applicationContext.xml
  • The spring configuration file is placed in the: resource directory
  • The spring configuration file needs to introduce a namespace (constraint)
  • <bean>Define the object id and the full class name of the implementation class through tags in the spring configuration file

Create the applicationContext.xml configuration file in the resource directory

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">
    
    <!--
        定义配置信息
            id:唯一标志(获取的时候,调用容器的getBean("id"))
            class:实现类的全限定类名
    -->
    <!--把数据库连接池对象放入IOC容器-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--把QueryRunner放入到IOC容器中-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
    	<constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--把dao对象交给IOC容器-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
    	<property name="queryRunner" ref="queryRunner"/>
    </bean>
    <!--把service交给IOC容器-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    	<property name="accountDao" ref="accountDao"/>
    </bean>
</beans>

test

import cn.test.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试从容器中获取对象
 */
public class UserDaoTest {
    
    

    public static void main(String[] args) {
    
    
        //1、根据配置文件获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、调用容器的方法,获取对象
        UserDao userDao = (UserDao)ac.getBean("userDao");
        //3、测试
        userDao.save();
    }
}

Perform process analysis

insert image description here

Initialize the Spring Bean object (xml)

Method 1: Default parameterless constructor

The IOC container is invoked through reflection to create a class object according to the default no-argument constructor. If there is no default no-argument constructor in the bean, the creation will fail.

<bean id="userDao" class="cn.test.dao.impl.UserDaoImpl"></bean>

Method 2: Create objects in factory mode

Objects can also be created through the factory pattern in Spring. There are two types of factory patterns:

  • Static factory: does not generate an instance of the factory, directly calls the static method of the factory to create the object
  • Instance factory: first generate an instance of the factory, and then call the method of the factory instance to create the object

(1) java code writing factory class

public class FactroyCreateBean {
    
    
    // 静态工厂
    public static UserDao createUserDao(){
    
    
    	return new UserDaoImpl();
    }
    // 实例工厂
    public UserDao createUserDaoSimple(){
    
    
    	return new UserDaoImpl();
    }
}

(2) xml configuration file configuration

<!--使用静态工厂创建对象-->
<bean id="userDao1" class="cn.test.factory.FactroyCreateBean" factory-method="createUserDao"/>
<!--使用实例工厂创建对象-->
<bean id="factroyCreateBean" class="cn.test.factory.FactroyCreateBean"/>
<bean id="userDao2" factory-bean="factroyCreateBean" factory-method="createUserDaoSimple"/>

Spring Bean life cycle

Overview, Lifecycle Flowchart

The Bean object life cycle refers to the period from the creation to the destruction of the Bean.

Coarse-grained life cycle:

  • The life cycle of a singleton object in spring is:

    Born: born when the IOC container is loaded

    Survival: Survival when the IOC container is running

    Died: Died when the IOC container is destroyed

  • The life cycle of multiple instances of objects in spring is:

    Birth: Birth when using the object

    Survival: always alive

    Death: Negative by the java garbage collector


Fine-grained life cycle:

birth process

  1. Instantiate bean object [IOC]

  2. Assign value to object attribute [DI]

  3. Handle the implemented Aware interface

    ① If the Bean has implemented the BeanNameAware interface, the setBeanName(String beanId) method implemented by it will be called, and the id value of the Bean in the Spring configuration file is passed here.

    ② If the Bean has implemented the BeanFactoryAware interface, it will call the setBeanFactory() method it implements, passing the Spring factory itself.

    ③ If the Bean has implemented the ApplicationContextAware interface, it will call the setApplicationContext(ApplicationContext) method and pass in the Spring context.

  4. Preprocess the bean object through the postProcessBeforeInitialization method of the BeanPostProcessor interface

  5. Process the bean object through the afterPropertiesSet method of the InitializingBean interface

  6. Process the bean object by specifying the init-method method

  7. The bean object is post-processed through the postProcessAfterInitialization method of the BeanPostProcessor interface. In this step, the bean object has been completely created successfully, and some work similar to caching can be done.

death process

  1. If the Bean implements the DisposableBean interface, its implemented destroy() method will be called.
  2. If the destroy-method method is specified, it can be executed automatically before the bean object is destroyed.

Life cycle flowchart

insert image description here

Test Case:

public class UserDaoImpl implements UserDao, BeanNameAware, BeanFactoryAware,ApplicationContextAware, InitializingBean, DisposableBean {
    
    
    public UserDaoImpl() {
    
    
    	System.out.println("IOC");
    }
    
    private Integer id;
        public void setId(Integer id) {
    
    
        System.out.println("DI");
        this.id = id;
    }
    
    @Override
    public void setBeanName(String s) {
    
    
        System.out.println("BeanNameAware:"+s);
    }
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    
    
    	System.out.println("BeanFactoryAware");
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
    	System.out.println("ApplicationContextAware");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
    
    
    	System.out.println("InitializingBean的afterPropertiesSet");
    }

    public void initMethod(){
    
    
    	System.out.println("init-method");
    }
    
    @Override
    public void save() {
    
    
    	System.out.println("保存成功!");
    }
    
    @Override
    public void destroy() throws Exception {
    
    
    	System.out.println("DisposableBean的destroy");
    }
    
    public void destroyMethod(){
    
    
    	System.out.println("destroy-method");
    }
}
public class MyBeanProcessor implements BeanPostProcessor {
    
    
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
    	System.out.println("BeanPostProcessor的before");
    	return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println("BeanPostProcessor的after");
        return bean;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="initMethod" destroy method="destroyMethod">
        <property name="id" value="1"/>
    </bean>
    <bean class="com.itheima.processor.MyBeanProcessor"/>
</beans>
// 测试类
public class UserDaoImplTest {
    
    
    @Test
    public void save() {
    
    
        ClassPathXmlApplicationContext ac = new
        ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = ac.getBean(UserDao.class);
        userDao.save();
        ac.close();
    }
}

Scope of Spring Beans

Reference: https://blog.csdn.net/weixin_38676276/article/details/90382350

  • singleton : singleton. There is only one shared Bean instance in the Spring IOC container. Defaults

    When spring creates the applicationContext container, spring will initialize all instances of the scope, plus lazy-init can avoid preprocessing

  • prototype : prototype (multiple instances)

    Each time the Bean is called from the container, a new instance is returned, that is, each call to getBean() is equivalent to executing new XxxBean()

    After creation, spring will no longer manage it

    (The following is the scope only used under the web project)

  • request : valid only within the current HTTP request

    A new bean is created for each HTTP request

    After the spring is created, it will continue to listen, and the instance will be destroyed when the request is processed.

  • session : valid only within the current HTTP Session

    The same HTTP Session shares a Bean, and different Sessions use different Beans

    After the spring is created, it will continue to listen. When the HTTP Session is finally discarded, the beans in the scope of the HTTP Session will also be discarded.

  • global-session : the global web domain. Similar to application in servlet. Generally used in Portlet application environment


Define Bean configuration information (xml)

  • id: unique flag (when getting it, call the container's getBean("id"))

  • class: The fully qualified class name of the implementing class

  • scope: object scope (singleton (default) | prototype | request | session | global-session)

  • init-method: After the object is successfully created, the specified initialization method

  • destroy-method: The destruction method executed before the container closes the object and destroys it

    Only valid when scope=singleton (singleton)

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype" 
      init-method="init" destroy-method="destroy"/>

dependency injection (xml)

Dependency injection : Dependency Injection (DI). It is the specific implementation of the core IOC of the spring framework. When writing a program, through the inversion of control, the creation of the object is handed over to spring, and then the dependent object is injected when the object is needed in the code.

IOC has two functions: dependency lookup, dependency injection

Essence: Assigning values ​​to private properties in objects

  • Construction method

  • set method call


constructor injection

  • Add a parameterized constructor to an object
public class UserServiceImpl implements UserService {
    
    

    private String name;
    private Integer age;

    public UserServiceImpl(String name, Integer age) {
    
    
        this.name = name;
        this.age = age;
    }

    @Override
    public void save() {
    
    
        System.out.println(name + age);
    }
}
  • In the spring configuration file, configure object creation through bean tags (need to add constructor parameters)
    <!--
        constructor-arg 设置对象的构造方法参数 (一个参数配置一个constructor-arg标签)
            name:构造参数名
            type:构造参数类型
            index:构造参数,参数索引位置(从0开始)
            以上三个属性,用于定位构造方法参数位置(三选一即可)
            value: 对基本数据类型的参数赋值(8大数据类型 + String)
            ref: 对对象属性的参数赋值。即必须得是在配置文件中配置过的bean
            以上两个属性,用于对构造参数赋值
     -->
    <bean id="userService" class="cn.test.service.impl.UserServiceImpl">
        <constructor-arg name="age" value="12"></constructor-arg>
        <constructor-arg name="name" value="王者荣耀"></constructor-arg>
    </bean>

set method injection

  • Provide the set method of the property

  • In the spring configuration file, the set method is called by combining the bean with the property configuration

    <bean id="book" class="com.itheima.spring.Book">
        <!--	name:找的是类中 set 方法后面的部分
    			ref:给属性赋值(其他bean类型)
    			value:给属性赋值(8大基本数据类型 + string类型)
    	-->
        <property name="name" value="程序员" />
        <property name="price" value="1" />
        <property name="publishDate" ref="date" />
    </bean>
    

Inject complex types (collections)

To pass values ​​to the collection members in the class, it also uses the set method injection method, but the data types of the variables are all collections. Here is an introduction to injecting arrays, Lists, Sets, Maps, and Properties.

(1) Inject array data

Configure the set method

public class UserServiceImpl implements UserService {
    
    

    /**
     * 注入数组(array数组,list集合,set集合)
     */
    private String [] names;
    private List<String> lists;
    private Set<String> sets;

    public void setNames(String[] names) {
    
    
        this.names = names;
    }

    public void setLists(List<String> lists) {
    
    
        this.lists = lists;
    }

    public void setSets(Set<String> sets) {
    
    
        this.sets = sets;
    }

    @Override
    public void save() {
    
    
    }
}

spring configuration file

<bean id="book" class="com.itheima.spring.Book">
	<!-- List -->
	<property name="list">
		<list>
			<value>1</value>
			<value>2</value>
		</list>
	</property>

	<!--Set-->
	<property name="set">
		<set>
			<value>3</value>
			<value>4</value>
		</set>
	</property>

	<!--数组-->
	<property name="array">
		<array>
			<value>5</value>
			<value>6</value>
		</array>
	</property>

	<!--Map-->
	<property name="map">
		<map>
			<entry key="7" value="7-1" />
			<entry key="8" value="8-1" />
		</map>
	</property>

	<!--Properties-->
	<property name="properties">
		<props>
			<prop key="9">9-1</prop>
			<prop key="10">10-1</prop>
		</props>
	</property>
</bean>

Annotation configuration in the Spring framework

Correspondence between introduction, annotation and xml configuration

  • Annotation and xml are two configuration forms provided by Spring. The functions of the two are exactly the same, and both are to reduce the coupling between programs.

  • The advantage of annotations is that the configuration is simple, and the advantage of xml is that the configuration does not need to change the source code, and the two methods can be used flexibly in enterprise development

  • Annotation configuration in Spring

    1. Annotation + xml configuration (enable annotation support)
    2. Pure annotations (Spring Boot + cloud))
  • Note: To use annotation development in spring, you need to enable the functional support of annotations (ioc annotations, aop annotations, transaction annotations)


Correspondence between annotations and xml configuration :

xml configuration Annotation configuration illustrate
< bean id=“” class=“” > @Component @Controller @Service @Repository Put the instantiated object of the class into the Spring container management
< property name=“” ref=“”> @Autowired @Qualifier @Resource Get object injection properties from Spring container
< property name=“” value=“”> @Value Simple property injection of beans
< bean scope=“”> @Scope Control the scope of the bean
< bean init-method=“init”
destroy method=“destory” />
@PostConstruct @PreDestroy Methods called after bean creation and before destruction

Enable package scanning (enable IOC annotation support)

Enable package scanning (that is, enable support for IOC annotations):

  1. Scan Spring annotations in all java classes under the specified package
  2. If IOC annotations on the class are scanned, the current class will be handed over to the IOC container for management. When the container starts, the object will be automatically created and stored in the container
  3. If the scan finds that there are DI annotations on the property, inject values ​​into the property according to the rules of dependency injection

Method 1: Enable package scanning in xml configuration mode

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
			    http://www.springframework.org/schema/beans/spring-beans.xsd
			    http://www.springframework.org/schema/context
			    http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启包扫描
		 - base-package:包名(自动扫描此包以及此包下的所有子包)
	-->
    <context:component-scan base-package="cn.test"></context:component-scan>
</beans>

Method 2: Configure class annotations to enable package scanning

/**
 * 1、声明配置类:@Configuration
 * 2、开启包扫描:@ComponentScan
 */
@Configuration
@ComponentScan(basePackages = "cn.test")
public class SpringConfig {
    
    
}

IOC annotations (annotations for object creation)

IOC annotation (annotation for object creation) description:

  • Marked on the class that wants to be managed by the IOC container, indicating that the creation of the object is handed over to the container management

  • When the Spring container starts, it automatically scans the IOC annotations according to the package scanning configuration, creates the annotated objects by reflection, stores them in the container, and delegates container management

  • The id (unique identifier) ​​stored in the container by default is the lowercase initials of the current class name. You can customize the id of the object stored in the container through the value attribute

There are four in total:

  •  **@Controller**:一般标注在表现层(web层)的类上
    
  •  **@Service**: 一般标注在业务层(service层)的类上
    
  •  **@Repository**: 一般标注在持久层(dao层)的类上
    
  •  **@Component**:组件, 非三层模式范围的类上使用
    

Equivalent to the following configuration in xml

<bean id="userDaoImpl" class="cn.test.dao.impl.UserDaoImpl"></bean>

Notes about the life cycle

  • @Scope : Configure the scope of the object on the class

    Specify the scope (singleton|prototype) through the value attribute, and the default is singleton (singleton)

  • @PostConstruct : The trigger action after the configuration object is created

    A method that is executed automatically when the object is created. Equivalent to the init-method in the xml configuration file

  • @PreDestroy : The trigger action before the configuration object is destroyed (only valid when Scope = singleton)

    The method executed before the container is closed and the object is destroyed. Equivalent to the destroy-method in the xml configuration file

Example:

@Repository
@Scope(value="singleton")
public class UserDaoImpl implements UserDao {
    
    

    public UserDaoImpl() {
    
    
        System.out.println("创建UserDaoImpl");
    }

    @Override
    public void save() {
    
    
        System.out.println("调用dao保存数据");
    }


    //初始化方法:在对象创建完成之后执行
    @PostConstruct
    public void init() {
    
    
        System.out.println("执行init方法");
    }

    //销毁方法:在容器关闭对象销毁之前执行
    @PreDestroy
    public void destory() {
    
    
        System.out.println("执行destory方法");
    }
}

DI annotations (annotations for dependency injection)

DI annotations are equivalent to directly assigning values ​​​​to attributes without resorting to set methods or constructors

@Autowired

Usage 1: mark on the attribute

  • Assign values ​​directly to properties (through @Autowired dependency injection, no need to configure set methods)

  • The default is to look up the object from the IOC container in the form of by Type (according to the type, that is, the interface type) and inject values ​​into the properties

  • If there are multiple objects of the same type as the attribute in the IOC container (one interface has multiple implementation classes),

    • It will look up the object from the container according to the attribute name (by Name) as the unique identifier and inject the value into the attribute

    • It can also be used together with the @Qualifier annotation to specify a unique flag to find objects from the container and inject values ​​​​to properties

      • value: specifies the unique identifier (id) of the object in the IOC container

      Note : @Qualifier can only be used in conjunction with @Autowired

Usage 2: marked on the method

  • Indicates that the current method is automatically executed. If the method has parameters, it will automatically find objects of the same type from the IOC container to pass values ​​to the parameters.
  • You can also add @Qualifier("object id in the IOC container") annotation to the parameter to find the object by name and pass the value to the parameter

Notes on using @Autowired

  1. The @Autowired annotation can only be used in classes managed by the Spring container (annotated with IOC annotations such as @Controller)

  2. Automatic injection has nothing to do with permission modifiers, even private modified fields can be automatically injected

  3. By default, properties automatically injected using the @Autowired annotation must be assembled (Spring container hosting)

    If no bean of this type can be found in the container for injection, an error will be reported

    If it is not allowed to be assembled, you can set the required attribute of @Autowired to false

  4. @Autowired is a type-based injection. If the current type property has only one Bean in the container, the property name is not limited, but it is generally recommended to follow the rule of lowercase first letter of the class name

  5. If the current property type has multiple beans in the container, the Bean name must be specified by the property name or @Qualifier annotation at the same time


Example:

@Service
public class UserServiceImpl implements UserService {
    
    
    @Autowired
    @Qualifier(value = "userDao2")		// 从容器中获取指定唯一标志的对象
    private UserDao userDao;

    @Override
    public void save() {
    
    
        userDao.save();
    }
}

@value

Configured on properties. Can be used for injection of simple data types, equivalent to < property name="" value="" >, but usually not used in this way

Generally used to parse the contents of the properties configuration file or registry configuration file

  • Obtain the corresponding value according to the key value, syntax rules: @Value(“${key}”)
  • Steps for usage:
    1. The properties configuration file is handed over to the Spring container for management
    2. Through @Value, get the configuration item from the container and inject it

Example:

(1) Configure the jdbc.properties file

jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23

(2) The configuration file is handed over to Spring

Modify the spring configuration file applicationContext.xml

    <!--将properties文件,交给spring管理-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>

(3) Attribute injection

@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
    
    

    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;

    public void save() {
    
    
        System.out.println(username);
        System.out.println(password);
        System.out.println(driver);
        System.out.println(url);
        System.out.println("调用dao11111完成保存");
    }
}

@Reource (understand)

The dependency injection annotation provided by jdk, which has been removed in jdk9 and above

  • can only be placed on attributes
  • Indicates that the attribute name is first matched with the object id in the IOC container to inject a value into the attribute [by name]
  • If not successful, it will continue to inject values ​​according to the type of the current attribute to match the same type of object in the IOC container [by type]
  • If the name attribute @Resource(name = "object id") is specified, the value can only be injected according to the object id

Example:

@Service
public class UserServiceImpl implements UserService {
    
    
    @Resource(name = "userDao1")
    private UserDao userDao;

    @Override
    public void save() {
    
    
        userDao.save();
    }
}

Configuration configuration class (annotation)

Common annotations in configuration classes:

  • @Configuration : Annotated on the class, declaring the class as a Spring configuration class

    When Spring starts, it will automatically scan and load all configuration classes, configure the Spring container (application context), and put the Bean in the configuration class into the container management

  • @Bean : Annotated on the method in the Spring configuration class, registering the bean object to the IOC container

    • name attribute: specify a unique flag for the generated bean

    When the Spring container starts, it automatically scans and executes all methods configured with @Bean, and stores the return value in the Spring container

    Notice:

    • The marked method needs to return an instance
    • The marked method can configure dependent attribute parameters, and Spring will automatically obtain the dependent object from the container and automatically call the method
  • @ComponentScan : Turn on package scanning (supported by Spring IOC annotations), and scan all classes under the current package and sub-packages by default

    • basePackage attribute: Specifies the scanned package path. can reduce loading time

    If IOC annotations on the class are scanned, the current class will be handed over to the IOC container for management. When the container starts, the object will be automatically created and stored in the container

    If the scan finds that there are DI annotations on the property, inject values ​​into the property according to the rules of dependency injection

  • @PropertySource : Load local properties files to Spring container management

    • value attribute: specify the local properties path
  • @Import : Import the content of other configuration classes in a configuration class

    • value attribute: specify the class class path of other configuration classes

    Spring supports multiple configuration classes (modules of configuration classes). If the configuration class is bloated, you can split the configuration class and then introduce sub-configuration classes into the main configuration class (no configuration annotations are required on sub-configuration classes)

Example:

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;

@Configuration		// 声明配置类
@ComponentScan(basePackages = "cn.test")	// 开启包扫描,并指定包扫描路径
@PropertySource(value="jdbc.properties")	// 通过注解将此文件交给spring容器管理
@Import(value=DataSourceConfig.class)		// 引入其他的配置类
public class SpringConfig {
    
    

    @Bean
    public QueryRunner getQueryRunner(DataSource dataSource) {
    
    
        QueryRunner qr = new QueryRunner(dataSource);
        return qr;
    }
}
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;

// 子配置类
public class DataSourceConfig {
    
    

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driver}")
    private String driver;

    @Bean
    public DataSource getDataSource() {
    
    
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
}
# properties文件
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23

AOP (Aspect Oriented Programming)

concept

AOP ((Aspect Oriented Programming) Aspect Oriented Programming

  • It is an idea, the purpose is to enhance the original function without modifying the source code
  • A technology for unified maintenance of program functions through precompilation and runtime dynamic proxy
  • AOP is a programming paradigm, a continuation of OOP, and horizontal development is carried out on the basis of OOP.
  • What AOP studies is not how to develop each layer, but the common functions between modules on the same layer. For example: transaction, log, statistics

Spring AOP is an implementation of the AOP idea. It encapsulates the logic that has nothing to do with the business but is shared by the business modules, reduces the duplication of code in the system, and reduces the coupling between modules. In addition, AOP can also solve some system-level problems, such as logs, transactions, permissions, etc.

The bottom layer of Spring is AOP implemented through dynamic proxy. Support jdk and cglib dynamic proxy at the same time, Spring will automatically select the proxy method according to whether the proxied class has an interface:

  • If there is an interface, use JDK dynamic proxy (you can also force the use of CGLIB dynamic proxy)

  • If there is no interface, use CGLIB dynamic proxy method


Spring AOP workflow :

Develop separately in the development phase, assemble and run in the operation phase

  • Development phase (completed by developers)

    • Develop common functions and make them into enhancements

    • Develop non-common functions and make them into pointcuts

    • In the configuration file, declare the relationship between the pointcut and the enhancement, that is, the aspect

  • Run phase/container start phase (AOP complete)

    1. Spring reads the aspect information in the configuration file, and according to the description in the aspect, adds enhanced functions to the point-cutting method of the target object, and dynamically creates proxy objects
    2. Finally, put the proxy object into the container (note: the dynamic proxy object is stored in the container!)

Terms and Descriptions

  • Target object (target): the object that needs to be enhanced, that is, the object where the pointcut method is located

  • Connection point (jointPoint): the method in the proxy object

  • PointCut : According to the rules of AOP to cut (match) the connection point, the matched point is called pointCut, that is, the method that needs to be enhanced

    • Pointcut expression: execution (method modifier return value type package name. class name. method name (parameter))

      The role of the pointcut expression: define a set of rules for selecting the pointcut (enhanced method) in the connection point (all methods)

      Wildcards are supported:

      *		// 一个或多个任意字符
      ..		// 配置到参数上,标识任意参数
      
    1. Method modifiers can be omitted
    2. The return value of the method can identify any return value type by *
    3. The package name can identify any package by *
    4. The class name can identify any class by *
    5. The method name can identify any method by *
    6. Arguments can be identified by any argument
    // 切入点的全统配方式,表示整个项目中所有类中所有方法都要被增强
    execution(* *..*.*(..))
    // 最常用的切入点表达式:精确到具体包路径
    execution(* com.test.controller.*.*(..))
    
  • Enhancement ( advice): A specific enhancement. Where does the enhanced method execute in the pointcut method

    Spring AOP advice (enhancement) is divided into 5 types:

    • Pre-advice (before): Execute before the pointcut runs

    • After-returning: Executed after the normal operation of the pointcut ends

    • Exception notification (after-throwing): executed when an exception occurs at the pointcut

    • final advice (after): at the final execution of the pointcut

    • Surround notification (around): a special notification that defines multiple enhanced logic in one method (similar to manually defining dynamic proxies)

      Custom methods to wrap around notifications:

      1. Parameter ProceedingJoinPoint: the method of the proxy object
      2. Return value: the return value of the enhanced method
  • Proxy object (proxy): The target object is enhanced to become a proxy object

  • Aspect : It is a design concept that includes Advice and Pointcut. Aspect = entry point + enhancement

    Advice defines the task of Aspect and when to execute it, and Pointcut defines where to cut in

    That is, what kind of enhanced function does Aspect define, and where does it cut into which core method?

  • Weaving : An action. The process of adding enhanced code to the core code is called weaving


Configure Spring AOP (xml)

xml file configuration entry point

  • <aop:pointcut
    • id: the unique identifier of the current pointcut
    • expression: pointcut expression

xml file configuration aspect

  • <aop:aspect : Configure an aspect
    • id: the unique identifier of the current aspect
    • ref: specifies which advice to use for the current aspect

xml file configuration notification type

  • <aop:before: specifies where the advice is executed in the pointcut method
    • method : the enhanced method name in the aspect class
    • pointcut-ref: the id of the pointcut

xml file configuration AOP example

	<!--声明AOP配置-->
    <aop:config>
        <!-- 配置切入点(被增强的方法) -->
        <aop:pointcut id="pt" expression="execution(* cn.test.dao.impl.*.*(..))"/>

        <!--配置切面-->
        <aop:aspect ref="logger">
        	<!-- 配置通知类型 -->
            <!-- 前置通知 -->
            <aop:before method="before" pointcut-ref="pt"></aop:before>
            <!-- 后置通知 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pt"></aop:after-returning>
            <!-- 异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"></aop:after-throwing>
            <!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="pt"></aop:after>-->
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pt"></aop:around>
        </aop:aspect>
    </aop:config>
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 切面类:此类中具有所有的增强代码逻辑
 */
public class Logger {
    
    

    /**
     * 前置通知:执行被代理对象方法之前执行
     * 方法:无参数,无返回值
     */
    public void before() {
    
    
        System.out.println("执行前置通知");
    }

    /**
     * 后置后置:正常执行被代理对象方法获取返回值之后执行
     */
    public void afterReturning() {
    
    
        System.out.println("执行后置通知");
    }

    /**
     * 异常通知:执行代码抛出异常的时候执行
     */
    public void afterThrowing() {
    
    
        System.out.println("执行异常通知");
    }


    /**
     * 最终通知:finally代码块中执行的逻辑
     */
    public void after() {
    
    
        System.out.println("执行最终通知");
    }

    /**
     * 环绕通知:在一个方法中定义多个增强逻辑
     */
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    
    
        Object obj = null;

        try {
    
    
            System.out.println("执行前置通知");
            //执行被代理对象方法
            obj = pjp.proceed();
            System.out.println("执行后置通知");
        }catch (Exception e){
    
    
            System.out.println("执行异常通知");
        }finally {
    
    
            System.out.println("执行最终通知");
        }
        return obj;
    }

Configure Spring AOP (annotation)

There are two types of AOP annotations:

  • Configuration method based on XML combined with annotations
  • Configuration method based on pure annotation

Enable AOP annotation support (xml mode)

xml configuration file

  • Enable support for IOC annotations, package scanning
    • Customized objects, object creation and dependency injection through IOC annotations
    • Third-party objects, object creation and dependency injection through XML configuration
  • Enable AOP annotation support, automatic proxy
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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 base-package="cn.test"></context:component-scan>

    <!--开启对AOP注解的支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!--在切面类中通过注解完成AOP配置-->
</beans>

Enable AOP annotation support (configuration method)

  • @EnableAspectJAutoProxy : marked on the configuration class to enable aop annotation support
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 配置类
 */
@Configuration
@ComponentScan(basePackages = "cn.test")
@EnableAspectJAutoProxy
public class SpringConfig {
    
    
}

Aspect class (annotation)

  • @Aspect : Annotated on the custom class, declaring the aspect class

    Note: The aspect class also needs to be annotated with IOC annotations (@Component) and handed over to Spring container management

  • Configure the notification type by annotation on the notification (enhancement) method in the aspect class:

    • @Before : pre-advice
    • @AfterReturning : post notification
    • @AfterThrowing : exception notification
    • @After : final notification
    • @Around : Around the notification

    Attributes of notification annotations:

    • value / argNames attribute: pointcut expression or method name annotated by @Pointcut()

      	@Around("pt()")
          public Object around(ProceedingJoinPoint pjp)
      
  • @Pointcut : Annotated on the empty method in the aspect class, extracting the public pointcut expression

    • value / argNames attribute: pointcut expression
    • Notification annotation configuration method name () can introduce public pointcut expressions
        @Pointcut(value="execution(* cn.test.service.impl.*.*(..))")
        public void pt() {
          
          }
    
/**
 * 切面类:此类中具有所有的增强代码逻辑
 */
@Component
@Aspect
public class Logger {
    
    

    /**
     * 前置通知:执行被代理对象方法之前执行
     * 方法:无参数,无返回值
     */
    //@Before(value="execution( * cn.test.dao.impl.*.*(..) )")
    public void before() {
    
    
        System.out.println("执行前置通知");
    }

    /**
     * 后置通知:正常执行被代理对象方法获取返回值之后执行
     */
    //@AfterReturning(value="execution( * cn.test.dao.impl.*.*(..) )")
    public void afterReturning() {
    
    
        System.out.println("执行后置通知");
    }

    /**
     * 异常通知:执行代码抛出异常的时候执行
     */
   // @AfterThrowing("execution( * cn.test.dao.impl.*.*(..) )")
    public void afterThrowing() {
    
    
        System.out.println("执行异常通知");
    }


    /**
     * 最终通知:finally代码块中执行的逻辑
     */
    //@After("execution( * cn.test.dao.impl.*.*(..) )")
    public void after() {
    
    
        System.out.println("执行最终通知");
    }

    /**
     * 环绕通知:在一个方法中定义多个增强逻辑
     */
    //@Around("execution( * cn.test.dao.impl.*.*(..) )")
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    
    
        Object obj = null;
        try {
    
    
            System.out.println("1执行前置通知");
            //执行被代理对象方法
            obj = pjp.proceed();
            System.out.println("2执行后置通知");
        }catch (Exception e){
    
    
            System.out.println("3执行异常通知");
        }finally {
    
    
            System.out.println("4执行最终通知");
        }
        return obj;
    }
    
    // @Pointcut:抽取公共的切入点表达式
    @Pointcut(value="execution(* cn.test.service.impl.*.*(..))")
    public void pt() {
    
    }
}

Execution order of the four notifications

Reference: https://blog.csdn.net/qq_45193304/article/details/109430545

The execution sequence of Spring AOP's four major notifications (pre-, post-, exception, and final notification) is very complicated, and it is related to the Spring version, configuration sequence, and configuration method (xml | annotation), so it is recommended to use surround notifications !

The xml method configures the execution order of aop in the correct order:

try {
    
    
	// 前置通知(before) : 在切点运行之前执行
   
    // 切点执行,被代理对象方法调用
       
	// 后置通知(after-returning): 在切点正常运行结束之后执行
}catch (Exception e){
    
    
    // 异常通知(after-throwing): 在切点发生异常的时候执行
}finally {
    
    
    // 最终通知(after): 在切点的最终执行
}

Annotation method configures the execution order of aop in the correct order:

try{
    
    
    try{
    
    
        //@Before  -- 首先执行前置通知
        method.invoke(..); -- 然后执行切入点方法
    }finally{
    
    
        //@After  -- 再而肯定会执行最终通知 --- 注解配置的注意点
    }
    //@AfterReturning  -- 如果没有异常,则继续执行后置通知
    return;  -- 返回结果
}catch(){
    
    
    //@AfterThrowing  -- 如果有异常,则执行异常通知
}

Transaction Management in Spring

Spring supports two types of transaction management: programmatic transactions and declarative transactions . The official strongly recommends the use of declarative transactions.

  • Programmatic transaction: write business code and transaction code together, its coupling is too high, not used in development

  • Declarative transactions:

    • Declarative transactions are based on AOP.

      Its essence is to intercept before and after the method, create a transaction before the method starts, and commit or roll back the transaction according to the execution status after the method ends.

    • Advantages of declarative transactions: transaction code and business code can be completely separated and developed, and then run-time assembly and operation can be realized through configuration.

    • Insufficiency of declarative transactions: it can only be applied to the method level, and cannot be applied to the code block level like programmatic transactions


API related to transaction management in Spring

Transaction control in Spring is mainly implemented through these three APIs:

  • PlatformTransactionManager interface: transaction manager, responsible for transaction management, and its subclasses are responsible for specific work
  • TransactionDefinition interface: defines some related parameters of the transaction
  • TransactionStatus interface: represents a real-time status of transaction operation

The relationship between the three: the transaction manager performs transaction management by reading transaction definition parameters , and then generates a series of transaction states


PlatformTransactionManager interface:

  • A root interface for Spring transaction management, use its implementation class as a transaction manager (enhanced transaction processing function)

  • Interface method:

    // 获取事务的状态信息
    TransactionStatus getTransaction(TransactionDefinition def)
    // 提交事务
    void commit(TransactionStatus status)
    // 回滚事务
    void rollback(TransactionStatus status)
    
  • Common implementation classes:

    • DataSourceTransactionManager : used when using JDBC and MyBatis to persist data
    • JpaTransactionManager : used when using JPA for persistence (jpa, hibernate)
    • HibernateTransactionManager : used when using Hibernate to persist data
    • JtaTransactionManager : used when transactions span multiple transaction management sources [distributed transactions]

TransactionStatus interface:

  • A real-time state of transaction execution

  • interface method

    // 是否是新事物
    boolean isNewTransaction()
    // 是否有回滚点
    boolean hasSavepoint()
    // 设置为只回滚事务
    void setRollbackOnly()
    // 是否是只回滚事务
    boolean isRollbackOnly()
    // 刷新事务状态 
    void flush()
    // 事务是否完成
    boolean isCompleted()
    

TransactionDefinition interface:

  • Transaction definition information (transaction isolation level, propagation behavior, read-only transaction, timeout, etc.)

insert image description here

  • transaction isolation level

    • Configure transactions in Spring, supporting all 4 isolation levels

    • Default value: automatically select the appropriate configuration item for the current database

    • // 事务隔离级别相关【不设置事务隔离级别,可能引发脏读、不可重复读、幻读】
      ISOLATION_READ_UNCOMMITTED	读未提交	mysq1支持四种,默认可重复度
      ISOLATION_READ COMMITTED	读已提交	oracle支持两种(读己提交和串行化),默认是读已提交
      ISOLATION_REPEATABLE READ	可重复度
      ISOLATION SERIALIZABLE		串行化
      
  • **Transaction Propagation Behavior:** When describing multiple method nested calls, the called method supports transactions

    • PROPAGATION_REQUIRED = 0 (transactions are required, this is the default)

      If there is a transaction, join the current transaction. If there is no transaction, start a new transaction.

    • PROPAGATION_SUPPORTS = 1 (support transactions)

      If there is a transaction, join the current transaction. Runs non-transactionally if there is no transaction.

    • PROPAGATION_MANDATORY = 2 (mandatory transaction, not responsible for creating it yourself)

      If there is a transaction, join the current transaction. An exception is thrown if there is no transaction.

    • PROPAGATION_REQUIRES_NEW = 3 (must have new)

      Always start a new transaction. If there is a transaction, suspend the existing transaction and start a new transaction again.

    • PROPAGATION_NOT_SUPPORTED = 4 (does not support transactions)

      Always executes non-transactionally, suspending any existing transactions.

    • PROPAGATION_NEVER = 5 (forcing no transaction, I am not responsible for suspending)

      Always executes non-transactionally, throwing an exception if there is an active transaction

    • PROPAGATION_NESTED = 6 (nested transactions)

      Runs in a nested transaction if an active transaction exists. If there is no active transaction, a new transaction is started.

      Inner transactions depend on outer transactions. When the outer transaction fails, the action done by the inner transaction will be rolled back.

      The failure of the inner transaction operation will not cause the rollback of the outer transaction

  • Whether read-only transaction

    isReadOnly : true | false (default)

    Read-only transactions: only queries, no additions, deletions, or modifications. Read-only transactions can only be used with query methods

  • Transaction timeout

    TIMEOUT_DEFAULT = -1 : The timeout period of the transaction, which requires the support of the underlying database to use this configuration. The default value is -1, which means unlimited.

    Timeout: Use the default value


Declarative transaction (xml configuration transaction)

Complete declarative transaction configuration based on XML:

  • Configure the transaction manager to be managed by the Spring container (aspect class)
  • Configure Transaction Notifications
  • AOP for configuration transactions
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
             http://www.springframework.org/schema/tx
             http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--包扫描-->
    <context:component-scan base-package="cn.test"></context:component-scan>
    <!--自定义的java对象:注解-->

    <!--第三方jar包中的对象:xml-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///heima23"></property>
    </bean>

    <!--配置Spring中的事务-->
    <!--1、事务管理器交给容器管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 2、配置事务通知。配置service层中所有类中所有方法,对事务的要求(支持) 
			id="advice" :表示IOC容器中真正的通知对象的id
			transaction-manager="transactionManager" :表示指定当前要对哪个事务管理器进行配置
			如果事务管理器在IOC容器中的id为transactionManager,此配置可以省略。
	-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--
                <tx:method :指定目标对象中切入点的方法名指定方法对事务的要求
                    name :方法名称。支持通配符 *
                    isolation :事务的隔离级别
                    timeout :超时时间
                    propagation :传播行为(REQUIRED)
                    read-only :是否只读事务(false)
            -->
            <tx:method name="save*" propagation="REQUIRED" read-only="false"></tx:method>
            <tx:method name="update*"></tx:method>
            <tx:method name="delete*"></tx:method>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
            <tx:method name="*"></tx:method>
        </tx:attributes>
    </tx:advice>
    <!--3、事务的AOP配置-->
    <aop:config>
        <!--切入点表达式-->
        <aop:pointcut id="pt" expression="execution(* cn.test.service.impl.*.*(..))"/>
        <!--配置切面。<aop:advisor只有在spring的声明式事务配置时才能使用-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

Declarative transactions (annotations)

Enable transaction annotation support (xml mode)

  • In the XML configuration file, enable support for transaction annotations: transaction annotation driven
  • In the XML configuration file, create a transaction manager for container management
  • On classes or methods that require transactions, use the @Transactional annotation to configure transactions
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
			    http://www.springframework.org/schema/tx
			    http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--包扫描-->
    <context:component-scan base-package="cn.test"></context:component-scan>

    <!--开启事务注解的支持-->
    <tx:annotation-driven></tx:annotation-driven>

    <!--事务管理器交给容器管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--自定义的java对象:注解-->

    <!--第三方jar包中的对象:xml-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///test"></property>
    </bean>
</beans>

Enable transaction annotation support (configuration method)

  • @EnableTransactionManagement : marked on the configuration class to enable transaction annotation support
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;

@Configuration
@ComponentScan(basePackages = "cn.test")
@EnableTransactionManagement
public class SpringConfig {
    
    

    /**
     * 创建datasource
     */
    @Bean
    public DataSource getDataSource() {
    
    
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        dataSource.setUrl("jdbc:mysql:///test");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return dataSource;
    }

    /**
     * 创建jdbctemplate
     *  1、从容器中获取datasource
     *  2、调用方法
     */
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
    
    
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    /**
     * 创建事务管理器
     */
    @Bean
    public PlatformTransactionManager getManager(DataSource dataSource) {
    
    
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(dataSource);
        return manager;
    }
}

Use of declarative transaction annotations

  • @Transactional : configure transactions

    Common attributes:

    • rollbackFor attribute: Set the exception class array that needs to be rolled back. When an exception in the specified exception array is thrown in the method, the transaction will be rolled back

      • Specify a single exception class: @Transactional(rollbackFor=Exception.class)

      • Specify multiple exception classes: @Transactional(rollbackFor={RuntimeException.class, Exception.class})

    • readOnly attribute: whether to read-only transaction ( true | false (default value) )

    • propagation attribute: transaction propagation behavior ( SUPPORTS | REQUIRED (default value) )

    • transactionManager attribute: When multiple transaction managers are hosted in the Spring container, specify the bean name of the transaction manager

    • isolation attribute: Set the transaction isolation level of the underlying database, which is used to handle the concurrency of multiple transactions

      Usually the default isolation level of the database can be used, and there is basically no need to set it

    • noRollbackFor attribute: Set the exception class array that does not need to be rolled back. When the exception in the specified exception array is thrown in the method, the transaction will not be rolled back

    Labeling position description:

    • Marked on the class: all methods in this class have the same transaction configuration
    • Annotated on the method: the method has a transaction configuration
    • Mark on the class and method at the same time: the principle of proximity (the transaction configuration on the method takes effect)
import cn.test.dao.AccountDao;
import cn.test.domain.Account;
import cn.test.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(propagation = Propagation.SUPPORTS)
public class AccountServiceImpl implements AccountService {
    
    

    @Autowired
    private AccountDao accountDao;

    @Transactional
    //@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
    public void transfer(String sourceName, String targetName, float money) throws Exception {
    
    
        //1、根据账户名称查询两个账户
        Account sourceAccount = accountDao.findByName(sourceName); //转出账户
        Account targetAccount = accountDao.findByName(targetName); //转入账户
        //2、操作金额转换(转出账户扣除金额,转入账户添加金额)
        sourceAccount.setMoney(sourceAccount.getMoney() - money);
        targetAccount.setMoney(targetAccount.getMoney() + money);
        //3、更新账户
        accountDao.update(sourceAccount);
        int i=1/0;
        accountDao.update(targetAccount);
    }
}

expand

Spring integration unit testing

When you click run in the unit test, the underlying work is actually a runner. The default is the ParentRunner runner provided by junit. It does not know the Spring environment, which means that it cannot obtain beans from the Spring container.

If you want to get objects from Spring's container, you need to use the runner provided by Spring.

  • Introduce dependencies

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    
    <!--spring-junit 整合单元测试-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
    
  • @RunWith annotation: set the runner of the unit test, and specify the unit test running environment through the value attribute

    • JUnit4.class: Specifies to use JUnit4 to run
    • SpringJUnit4ClassRunner.class : Spring test environment
    • SpringRunner.class : Spring test environment

    Note:

    • SpringRunner extends SpringJUnit4ClassRunner.class

    • SpringJUnit4ClassRunner can be used when using JUnit4.12 or higher SpringRunner

      But it is recommended to use SpringRunner, final type, safe

    • Versions below JUnit 4.12 can only use SpringJUnit4ClassRunner

  • @ContextConfiguration annotation: specify the configuration information of the container

    • localtions attribute: configuration file path
    • classes attribute: configuration class
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountJunitTest {
    
    

    @Autowired
    private AccountService accountService;

    //测试保存
    @Test
    public void testInsert() {
    
    
        //3、调用方法保存
        Account account = new Account();
        account.setMoney(100f);
        account.setName("小李1");
        accountService.saveAccount(account);
    }
}

Modularization of configuration files

If the configurations are all configured in one applicationContext.xml file, when there are too many developers, if all the beans are configured in the same configuration file, the file will be huge and inconvenient to maintain. In response to this problem, Spring provides a way of multiple configuration files, which is the so-called modularization of configuration files.

  1. Multiple configuration files in parallel Write multiple configuration files directly, such as beans1.xml, beans2.xml..., and then directly pass in multiple configuration files
    when creating the ApplicationContext .
ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");
  1. Master-slave configuration files
    Accompany a master configuration file first, and then import other configuration files in it.
  <import resource="beans1.xml" />
  <import resource="beans2.xml" />

  <!--拓展:引入本地properties配置文件-->
  <context:property-placeholder location="classpath:db.properties"/>

Precautions:

  • The bean with the same name cannot appear in the same xml file, and an error will be reported if it appears
  • If there are beans with the same name in multiple xml files, no error will be reported, but the beans loaded later will overwrite the beans loaded earlier, so try to
    ensure that the bean names are unique during enterprise development.

High concurrency security issues of Spring Bean singleton

Spring’s beans are all singletons by default. In some cases, singletons are not safe for concurrency. Taking Controller as an example, the root of the problem is that if member variables are defined in the Controller, multiple requests come and all enter the Controller object of the same singleton.

raise a question

Visit this url multiple times, you can see that the result is self-incrementing each time, so such code is obviously not safe for concurrency.

@Controller
public class HomeController {
    
    
    private int i;
    @GetMapping("testsingleton1")
    @ResponseBody
    public int test1() {
    
    
        return ++i;
    }
}

solution

Solution 1: Try to avoid using member variables

Under business conditions, try to avoid using member variables and use local variables in methods


Solution 2: Use concurrency-safe classes

As a highly functional programming language, Java has rich APIs. If you must use member variables in singleton beans, you can consider using concurrency-safe containers, such as ConcurrentHashMap, ConcurrentHashSet, etc., and wrap member variables (usually such variables as the currently running task list) into these concurrency-safe containers for management.


Scenario 3: Concurrency Safety for Distributed or Microservices

If the impact of microservices or distributed services is further considered, solution 2 is not enough, so distributed cache middleware such as Redis that can share certain information can be used to ensure that different service instances of the same service have the same shared information (such as the currently running task list and other variables).


Solution 4: Singleton variable prototype

For web projects, you can add annotations @Scope("prototype") or @Scope("request") to the Controller class, and for non-web projects, add annotations @Scope("prototype") to the Component class.

Advantages: easy to implement

Disadvantage: It greatly increases the server resource overhead of bean creation, instantiation and destruction


Unavailable solution: thread isolation class ThreadLocal

The default request thread pool size of the web server is 10, and these 10 core threads can be reused by different Http requests later.

The ThreadLocal method can achieve thread isolation, but it still cannot achieve concurrency safety.


Use the @Autowired annotation to assign values ​​​​to static variables

describe:

Objects in the Ioc container may be used in some tool classes, and the member variables in the tool class are often static. At this time, annotations @Autowiredwill appear NullpointerException(null pointer exception).

Principle analysis:

Static variables and class variables are not attributes of objects, but attributes of a class, so static methods belong to classes, and ordinary methods belong to entity objects (that is, objects from New). Spring injection instantiates objects in containers, so static methods cannot be used.

The use of static variables and class variables expands the scope of use of static methods. Static methods are not recommended in spring. The main purpose of dependency injection is to let the container generate an instance of an object, and then use them throughout the life cycle, and it also makes the testing work easier.

Once the static method is used, there is no need to generate an instance of this class, which will make testing more difficult. At the same time, it is not possible to generate multiple instances with different dependent environments for a given class by means of injection. This static field is implicitly shared and is a global global state. Spring also does not recommend this.


**Solution 1: **Add the @Autowire annotation to the set method

@Component
public class Test {
    
    
    
    private static SessionFactory sessionFactory;
    
    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
    
    
        Test.sessionFactory = sessionFactory;
    }
}

**Solution 2:** Annotate with @PostConstruct

@Component
public class Test {
    
    
    
    private static SessionFactory sessionFactory;
    
    @Autowired
    private SessionFactory sessionFactory2;
    
    @PostConstruct
    public void beforeInit() {
    
    
        SessionFactory = sessionFactory2;
    }
}

**Solution 3: **Add the @Autowire annotation to the constructor

@Component
public class Test {
    
    
    
    private static SessionFactory sessionFactory;
    
    @Autowired
    public Test(SessionFactory sessionFactory) {
    
    
        Test.SessionFactory = SessionFactory;
    }
}

A class in a non-container calls a class in a container

describe:

When using @Autowired to inject objects, generally the injected classes are annotated with @Coponent, @Controller, @Service, @repository, etc. Both the injected class and the injected class are managed by spring and can be called. But when the non-container class (without the above annotation) uses @Autowired to call the class in the container, the injected object is empty and a null pointer exception is reported.

solution:

Create a tool class BeanUtils, the getBean in this tool class can get the class in the container, and use it in a non-container class

@Component
public class BeanUtils implements ApplicationContextAware {
    
    
    /**
     * 以静态变量保存ApplicationContext,可在任意代码中取出ApplicaitonContext.
     */
    private static ApplicationContext context;

    /**
     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
     */
    @Override
    public void setApplicationContext(ApplicationContext context) {
    
    
        BeanUtils.context = context;
    }

    public static ApplicationContext getApplicationContext() {
    
    
        return context;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.  方法返回值的类型由调用者决定
     */
    public static <T> T getBean(String name) {
    
    
        return (T) context.getBean(name);
    }

    /// 获取当前环境
    public String getActiveProfile() {
    
    
        return context.getEnvironment().getActiveProfiles()[0];
    }
}

Using container classes in non-container classes

public class StationFactory {
    
    
    Map<String, StationOperation> map = new HashMap<>();
    {
    
    
        map.put("定损中心主管指标表", BeanUtils.getBean("leadDSZXOperation"));
        map.put("定损中心员工指标表", BeanUtils.getBean("empDSZXOperation"));
        map.put("视频查勘中心主管指标表", BeanUtils.getBean("leadVideoSurveyCenterOperation"));
        map.put("视频查勘中心员工指标表", BeanUtils.getBean("empVideoSurveyCenterOperation"));
        map.put("视频定损中心主管指标表", BeanUtils.getBean("leadVideoDSCenterOperation"));
	}
}

Guess you like

Origin blog.csdn.net/footless_bird/article/details/126252162