1. Introduction to Spring
Spring is an open source design-level framework.
The solution is the loose coupling between the business logic layer and other layers, so it will run through the whole system application with Interface-oriented programming ideas.
Spring features:
1. Easy decoupling and simplified development
2. Support for AOP programming
3. Support for declarative transactions
4. Easy program testing
5. Easy integration of excellent frameworks
6. Reduce the difficulty of using the Java EE API
7.Java source code is a classic learning paradigm
II. IOC and DI
- IOC (Inversion of Control) Controls Reverse: Reverses the creation rights of objects to spring.
Principle: Factory Mode + Reflection
Use spring-IOC:
1. Add jar packages
2. Create a configuration file: The name is usually applicationContext.xml
3. Add Profile
4. Testing applications - DI (Dependency Injection) Dependency Injection: The process of assigning dependent properties to spring management classes through a configuration file. An IOC environment is required.
Creating objects through Spring configuration is IOC, and setting properties through Spring configuration is DI.
3. Profile applicationContext.xml
3.1 Basic Use
<!-- applicationContext.xml --> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--id Is any name you choose, class Is the full path to the interface implementation class--> <!--id="userDao"It can also be replaced by name="userDao", id: The unique constraint in the constraint is used and no special characters can appear. name: Special characters can appear without using the unique constraints in the constraints --> <bean id="userDao" class="demo1.UserDaoMysqlImpl" init-method="mysql_init" destroy-method="mysql_destroy"> <!--Dependent Injection: name: To inject the name of the property, value: Values assigned to attributes(Injection Value), Attributes to be injected need to be provided Setter Method. --> <property name="name" value="Zhang San"/> </bean> <!--init-method: Bean The method to execute when initialized. destroy-method: Bean When destroyed(That is, the factory closes)Method of execution, Methods are inside the class of the added object. Bean Created by singleton, scope:Bean Scope of action, default to singleton: Spring Objects are created in singleton mode with the following values: prototype: In multiple-case mode, objects are not destroyed by factory closure, but by garbage collection. request: Apply to web In the project, Spring After creating this class, save this class in request In scope, session: Apply to web In the project, Spring After creating this class, save this class in session In scope,--> <bean id="person" class="demo2.Person" init-method="init" destroy-method="destroy" scope="prototype"> <property name="name" value="May Fourth leader"/> </bean> <!--Import another configuration file--> <import resource="applicationContext2.xml"/> <import resource="applicationContext3.xml"/> </beans>
// Interface public interface UserDao { public void save(); public void delete(); } // Implementation Class public class UserDaoMysqlImpl implements UserDao { public String name; public void setName(String name) { this.name = name; } public void mysql_init(){ System.out.println("mysql_init"); } public void mysql_destroy(){ System.out.println("mysql_destroy"); } @Override public void save() { System.out.println("mysql-save"); } @Override public void delete() { System.out.println("mysql-delete"); } }
// Test Class public class Test{ @Test public void test(){ //1. Loading a configuration file: When a configuration file is loaded, objects are created and all objects added to the configuration file are created. //Use ClassPathXmlApplicationContext(), when placing the configuration file in the program. //Use FileSystemXmlApplicationContext() when the configuration file is elsewhere //Separate multiple profiles with commas ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. Get the object based on the id in the configuration file UserDao userDao = (UserDao)context.getBean("userDao"); //Using DI (Dependent Injection) to assign attributes in a class through a configuration file: assigning values in a configuration file System.out.println(dao.name); //Singleton mode: Close the factory and all objects will be destroyed context.close(); } }
3.2 How to instantiate an example in a configuration file
<!--Default construction method--> <!--<bean id="user" class="demo3.User"></bean>--> <!--Static factory instantiation: factory-method Indicates the static method of creating objects in a class--> <bean id="user" class="demo3.User" factory-method="createUser"/> <!--Instance factory instantiation: using factory-bean Point to another bean--> <bean id="user2" class="demo3.User" factory-bean="user"/>
3.3 How attributes are injected in the configuration file
<!-- Attribute Injection Method --> <bean id="student" class="demo4.Student"> <!--1.adopt set Attribute injection for methods: those that provide attributes in a class Setter Method <property name="name" value="Li Dazhao"/> <property name="age" value="20"/> --> <!--2.Attribute injection as a construction method--> <constructor-arg name="name" value="Li Dazhao_Construction method"/> <constructor-arg name="age" value="22"/> <!--3.Attribute injection of reference type: ref Refers to the introduction dog Of bean--> <!--<property name="dog" ref="dog"/>--> <!--Can be used p:dog-ref="dog"replace--> <property name="dog" value="#{dog2} "/> <!--Use value without ref--> <property name="dogName" value="#{dog2.name}'/> <!!--Assign values to the current bean field with fields from other beans--> <!--Property injection for collection type: To provide Setter Method--> <!--array--> <property name="attr"> <list> <value>Zhang San</value> <value>Li Si</value> <value>King Five</value> </list> </property> <!--list aggregate--> <property name="myList"> <list> <value>123</value> <value>Li Dazhao</value> </list> </property> <!--set aggregate--> <property name="mySet"> <set> <value>000</value> <value>222</value> </set> </property> <!--map aggregate--> <property name="myMap"> <map> <entry key="key1" value="value1"></entry> <entry key="key2" value="value2"></entry> </map> </property> </bean> <!--4.Use p Property injection for name control: can be omitted property,Form: p:Field name="value", Need to be introduced: xmlns:p="http://www.springframework.org/schema/p" --> <bean id="dog" class="demo4.Dog" p:name="Small White" p:age="3" p:color="white"> <!-- <property name="name" value="Small White"/> <property name="age" value="3"/> <property name="color" value="white"/> --> </bean> <!--5.EL Attribute injection in the form of an expression:#{value},Strings are enclosed in single quotes, referencing other bean: #{id value of other bean s}--> <bean id="dog2" class="demo4.Dog"> <property name="name" value="#{'Rhubarb'}'/> <property name="age" value="#{5}"/> <property name="color" value="#{'yellow'}"/> </bean>
4. @Component Comment
Class injection can be implemented using the annotation @Component on the class
@Component derives three annotations: these three annotations function similarly,
-
@Controller: Used to label the web layer
-
@Service: used to label the service layer
-
@Repository: used to label the dao layer
<!-- configuration file --> <!--Specify packages for annotation scanning--> <!--<context:component-scan base-package="demo1"/>--> <!--XML Integrate development with annotations: In the absence of a scan, the line above is omitted. XML Administration Bean,Annotation Completes Attribute Injection--> <context:annotation-config></context:annotation-config> <bean id="person" class="demo1.Person"></bean>
@Component("user") //Equivalent to adding: <bean id="user" class="/> @Scope("prototype") //Declare multiple cases pattern public class User { /* Use annotation injection properties, which assign values to fields: a.Add @Value("value") directly to the field without providing a set method b.Provides a set method to add @Value("value") to the set method */ @Value("Zhang San") public String name; /* @Autowired //1.Attribute injection of reference type, automatically introduces other classes based on type injection, requires @Component annotation to be added to other classes @Qualifier("dog") //2.Combined with @Autowired injection based on the name in @Component, can be omitted */ @Resource(name="dog") //3. Equivalent to combining the two notes above public Dog dog; @PostConstruct //Initialized, equivalent to init-method in configuration file public void init(){ System.out.println("init----Initialization"); } @PreDestroy //Called when destroyed public void destroy(){ System.out.println("destroy----Destroy"); } }
5. AOP
5.1 AOP Internal Principles
5.1.1 JDK Dynamic Proxy
This proxy mode is the same as the dynamic proxy mode in design mode
Example:
// Interface Class public interface GoodsDao { public void save(); public String update(); public void delete(); public void find(); }
// Implementation Class public class GoodsDaoImpl implements GoodsDao { @Override public void save() { //check(); System.out.println("Save Operation"); } @Override public String update() { System.out.println("update operation"); return "update---res"; } @Override public void delete() { System.out.println("Delete operation"); } @Override public void find() { System.out.println("find"); int i=1/0; } // public void check(){ // System.out.println (Permission Check); // } }
// Dynamic Proxy Object //Internal AOP Principle: JDK Dynamic Proxy: By implementing the interface, the object being proxied must implement the interface //By using dynamic proxy objects, we can add the logic we want to add to the dynamic proxy class instead of adding the logic we want to the real object class, which improves the scalability of the code and reduces the coupling. public class GoodsJDKProxy { public GoodsDao createProxy(GoodsDao goodsDao){ //Enhance Classes /*Proxy The purpose of this class is to dynamically create a class of proxy objects First parameter: defines which ClassLoader object loads the generated proxy object The second parameter is an array of Interface objects, which represent the set of interfaces that will be provided to the objects that need to be proxied. If I provide a set of interfaces to it, then this proxy object claims to implement the interface (polymorphic), so I can call the methods in this set of interfaces Third parameter: Associate the proxy object to the InvocationHandler object */ GoodsDao goodsDaoProxy = (GoodsDao)Proxy.newProxyInstance(goodsDao.getClass().getClassLoader(), goodsDao.getClass().getInterfaces(), new InvocationHandler() { @Override //When an object is called, all methods will come here //Callback function: Each time a method in a proxy object executes, it comes to the callback function, which allows you to do something before the method executes /* proxy:The real object that we represent method:Refers to a Method object that we call a method of a real object args:Refers to parameters that are accepted when calling a method of a real object */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("save".equals(method.getName())){ //Validate permissions only before saving System.out.println("Permission Check----------"); GoodsDao goodsDao1 = (GoodsDao)method.invoke(goodsDao, args); System.out.println("Log Add"); return goodsDao1; } return method.invoke(goodsDao,args); } }); return goodsDaoProxy; } }
// Test Class public class GoodsTest { @Test public void test(){ GoodsDao goodsDao = new GoodsDaoImpl(); //goodsDao.save(); GoodsJDKProxy goodsJDKProxy = new GoodsJDKProxy(); //Get the proxy object GoodsDao proxy = goodsJDKProxy.createProxy(goodsDao); proxy.save(); proxy.update(); } }
5.1.2 Cglib Dynamic Proxy
Example:
// class public class UserDao { public void save(){ System.out.println("Preservation"); } public void update(){ System.out.println("To update"); } }
// proxy class //Internal AOP Principle: Cglib Dynamic Proxy: Using Inheritance public class UserDaoCglibProxy implements MethodInterceptor{ public UserDao createCglibProxy(UserDao userDao){ //1. Create Core Classes Enhancer enhancer = new Enhancer(); //2. Set parent class: With inheritance, a subclass is created that automatically inherits UserDao enhancer.setSuperclass(userDao.getClass()); //3. Set callback enhancer.setCallback(this); // this refers to the current class object, which is the instantiated object of the custom proxy class //4. Create a proxy object: that is, give you the subclasses you created UserDao obj = (UserDao)enhancer.create(); return obj; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if("save".equals(method.getName())){ System.out.println("Jurisdiction----------"); return methodProxy.invokeSuper(o,objects); } return methodProxy.invokeSuper(o,objects); } }
// Test Class public class UserDaoTest { @Test public void test(){ UserDao userDao = new UserDao(); //userDao.save(); UserDaoCglibProxy userDaoCglibProxy = new UserDaoCglibProxy(); UserDao cglibProxy = userDaoCglibProxy.createCglibProxy(userDao); cglibProxy.save(); cglibProxy.update(); } }
5.2 AOP Details
Introduction to 5.2.1 AOP
AOP: Aspect Oriented Programming, Face Oriented Programming. A technique for unified maintenance of program functions through precompilation and run-time dynamic agents.
AOP is the continuation of OOP, which can isolate parts of business logic, thus reducing the coupling between parts of business logic, improving the reusability of programs, and improving the efficiency of development.
AOP replaces the traditional vertical inheritance by the horizontal extraction mechanism: it does not destroy the original class, generates a proxy class, generates the proxy class automatically, enhances the original class, and can add or cancel the added functions at any time.
AspectJ: An AOP framework, Spring abandoned its traditional approach and introduced AspectJ as its own AOP development.
AOP-related terms:
-
Joinpoint: Connection points: Methods that can be intercepted, methods that can be enhanced, and these methods can be called connection points
-
Pointcut: Start Point: A Really Intercepted, Enhanced Approach
-
Advice: Notification: Added content (functionality), usually encapsulated in a method called notification
-
Introduction: Introduction: Increase at the class level, adding new attribute methods to existing classes, which are often enhanced in development
-
Target: Added object
-
Weaving: Weaving: The process of applying notifications to the target object
-
Proxy: Proxy object
-
Aspect: Aspect: A collection of multiple notifications and entry points
5.2.2 How to use AOP
AOP usage:
1. Introducing basic jar packages
2. Introducing related jar packages for aop development
3. Introducing aop constraints in configuration files
4.Spring test: Each time you test, you need to get the factory, import the spring-test.jar package, add the comment @Runwith and @ContextConfiguration, instead of having to get the factory manually every time
5. Testing
6. Write a facet class
7. Give the cut face to spring
8. Configure AOP completion to proxy targets
When using an interface, it is different from not using an interface internal proxy:
JDK dynamic proxy is used for interfaces, Cglib dynamic proxy is used for no interfaces
Example:
// Face class public class Myaspect { public void check(){ System.out.println("Permission Check"); } public void log(Object res){ System.out.println("Logging:"+res); } //Defining surround notifications added in the configuration file requires a return value and a parameter of type ProceedingJoinPoint public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Open Transaction"); Object result = joinPoint.proceed(); //Call the target method and execute, result is the result of execution of the target method System.out.println("Submit Transaction"); return result; } //Exception notification: You can add the parameter Throwable to get exceptions public void except(Throwable ex){ System.out.println("There are exceptions:"+ex.getMessage()); } public void after(){ System.out.println("Final Notification"); } }
<!-- configuration file --> <bean id="goodsDao" class="demo1.GoodsDaoImpl"/> <!--Use above JDK Classes in dynamic proxies--> <bean id="myaspect" class="demo3.Myaspect"/> <!--To configure aop--> <aop:config> <!--Start Point: Which method to enhance--> <!--expression: An entry point expression indicating the method to be enhanced in parentheses:[Access modifier] Method Return Value Type Package Name.Class name.Method Name(parameter), * : Represents any return value type,.. : Indicates that the parameter is arbitrary. * demo1.GoodsDaoImpl+save(..),+ : Represents the current class and subclass, * com.myxq..*.*(..): Express com.myxq All methods of the package and all classes below it --> <aop:pointcut id="savepoint" expression="execution(* demo1.GoodsDaoImpl.save(..))"/> <aop:pointcut id="savepoint2" expression="execution(* demo1.GoodsDaoImpl.update(..))" /> <aop:pointcut id="savepoint3" expression="execution(* demo1.GoodsDaoImpl.delete(..))" /> <aop:pointcut id="savepoint4" expression="execution(* demo1.GoodsDaoImpl.find(..))"/> <!--Configuration facets: what are the enhanced capabilities--> <aop:aspect ref="myaspect"> <!--Pre-notification: Define actions to be performed before the target method--> <aop:before method="check" pointcut-ref="savepoint"/> <!--Post-notification: Defines the action to be performed after the target method, returning: Returns a value whose value is method Medium method log Like the parameter name, the return value from the entry point method is received and passed to log Method --> <aop:after-returning method="log" pointcut-ref="savepoint2" returning="res"/> <!--Surround notification: actions to be performed before and after the target method--> <aop:around method="around" pointcut-ref="savepoint3"/> <!--Exception notification: The action performed when the target method has an exception. throwing: The method of throwing an exception, throwing it into an exception notification, has the same name as the parameter in the exception notification--> <aop:after-throwing method="except" pointcut-ref="savepoint4" throwing="ex"/> <!--Final exception: executes regardless of whether an exception occurs--> <aop:after method="after" pointcut-ref="savepoint4"/> </aop:aspect> </aop:config>
// Test Class //Instead of creating a factory each time, use the following two notes @RunWith(SpringJUnit4ClassRunner.class) //Let the tests run in the Spring test environment @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Resource(name="goodsDao") private GoodsDao goodsDao; @Test public void test(){ //Add a'permission check'before the save method in the configuration file and a'log record' after the update method this.goodsDao.save(); this.goodsDao.update(); this.goodsDao.delete(); this.goodsDao.find(); } }
5.2.3 AOP Annotation Style AspectJ Development
AOP annotation style AspectJ development:
1. Introducing the Jar package
2. Introducing a configuration file
3. Write Face Class Configuration
4. Enhancement with annotated AOP object target classes: Open AOP development as annotations in the configuration file: <aop:aspectj-autoproxy/>, add annotations on faceted classes: @Aspect
5. Annotate AOP notification type
6. Configuration of annotation entry points for AOP
7. Define multiple entry points
Example:
<!-- Open in Profile aop annotation --> <aop:aspectj-autoproxy/>
// Using annotations in custom facet classes @Aspect //Identifies the current class as a facet for the container to read public class GoodsDaoAspect { //Multiple entry points can be added with || //@Before(value="execution(* demo1.GoodsDaoImpl.save(..)) || execution(* demo1.GoodsDaoImpl.update(..))") //Short form: first you need to add a starting point with the @Pointcut comment @Before(value="GoodsDaoAspect.pointcut1() || GoodsDaoAspect.pointcut2()") public void log(){ System.out.println("Journal"); } @AfterReturning(value="execution(* demo1.GoodsDaoImpl.update(..))",returning = "res") public void afterreturning(Object res){ System.out.println("after returning advise:"+res); } @Around(value="execution(* demo1.GoodsDaoImpl.delete(..))") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Open Transaction"); Object proceed = joinPoint.proceed(); System.out.println("Submit Transaction"); return proceed; } @Pointcut(value="execution(* demo1.GoodsDaoImpl.save(..))") private void pointcut1(){} //It's like giving this note a name. @Pointcut(value="execution(* demo1.GoodsDaoImpl.update(..))") private void pointcut2(){} @Pointcut(value="execution(* demo1.GoodsDaoImpl.delete(..))") private void pointcut3(){} }
6. JDBC Templates
spring-JDBC template: Avoid complex and lengthy code caused by direct use of JDBC
1. Import jar packages: Spring develops jar packages for basic jar packages, database-driven packages, and JDBC templates, where the spring-tx... jar packages are transaction-related jar packages
2. Create databases and tables
3. Use JDBC templates
Use third-party open source connection pools: MySQL 8.0 recommends using mysql-connector-java-8.0 and above
1.DBCP:jar package:
com.springsource.org.apache.commons.dbcp
com.springsource.org.apache.commons.logging
com.springsource.org.apache.commons.pool
2.C3P0:jar package:
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
Note: c3p0 connection to mysql8.0 requires mysql-connector-java-8.0 and above
3.druid:jar package:
druid...
6.1 Create JDBC templates in the normal way
//1. Create a connection pool DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///spring?useSSL=false&serverTimezone=UTC"); dataSource.setUsername("root"); dataSource.setPassword("9853"); //Create Template JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.update("insert into account values(null,?,?)","Li Si",10000d);
6.2 Create JDBC templates using Spring configuration and annotations
Configuration file - applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!--Configure database connection pool--> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring?useSSL=false&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="9853"/> </bean> <!--To configure DBCP Connection pool: and above jdbc Comparing with, only modified class--> <bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring?useSSL=false&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="9853"/> </bean> <!--To configure C3P0 Connection pool: and jdbc Comparison: driverClassName->driverClass,url->jdbcUrl, username->user --> <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///spring?useSSL=false&serverTimezone=UTC"/> <property name="user" value="root"/> <property name="password" value="9853"/> </bean> <!--Load jdbc.properties Property files: the first way <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="jdbc.properties"/> </bean> --> <!--Second: First, some namespaces need to be introduced in the above constraints--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--To configure druid Connection pool: Once the property file has been loaded using the first method above, it can be used ${key}Get the contents of the file, After loading the properties file in the second way above, the following name Name and ${}In key Names can't be the same--> <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"/> <property name="url" value="${jdbcurl}"/> <property name="username" value="${jdbcusername}"/> <property name="password" value="${pwd}"/> </bean> <!--To configure JDBC Template--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druid"/> </bean> </beans>
Test class:
//Creating JDBC templates using Spring configuration and annotations @RunWith(SpringJUnit4ClassRunner.class) //Let the tests run in the Spring test environment @ContextConfiguration("classpath:applicationContext.xml") //Introduce configuration files, load configuration classes public class SpringJdbcTest2 { //Attribute Injection @Resource(name="jdbcTemplate") private JdbcTemplate jdbcTemplate; @Test public void test(){ jdbcTemplate.update("insert into account values(null,?,?)","Li Qingzhao",5000d); System.out.println("complete"); } @Test public void test2(){ //Query individual records //The second parameter is the data type to query out the data String s = jdbcTemplate.queryForObject("select name from account where id=?", String.class, 1); System.out.println(s); Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class); System.out.println(count); } @Test public void test3(){ //Query single object data Account account = jdbcTemplate.queryForObject("select * from account where id=?", new MyRowMap(), 1); System.out.println(account); } @Test public void test4(){ //Query all data List<Account> query = jdbcTemplate.query("select * from account", new MyRowMap()); System.out.println(query); } } class MyRowMap implements RowMapper<Account>{ @Override public Account mapRow(ResultSet resultSet, int i) throws SQLException { Account account = new Account(); account.setId(resultSet.getInt("id")); account.setName(resultSet.getString("name")); account.setMoney(resultSet.getDouble("money")); return account; } }
7. Spring - Transaction Management
7.1 Brief description of transaction management
Transaction Management API for Spring:
-
PlatformTransactionManager: The Platform Transaction Manager is an interface.
Implementation class: DataSourceTransactionManager: The underlying uses JDBC to manage transactions
HibernateTransactionManager: The underlying uses Hibernate to manage transactions . . .
-
TransactionDefinition: Transaction Definition Information: Information used to define the transaction's relevance, isolation level, timeout information, propagation behavior, read-only or not
-
TransactionStatus: Transaction status: An object used to record the status of a transaction during transaction management
Relationships between transaction management API s: When Spring conducts transaction management, the platform transaction manager first manages transactions based on transaction definition information. During the process of transaction management, various states are generated, and the information of these States is recorded in the object of transaction state.
Spring does not directly manage transactions, but rather provides a variety of transaction managers that delegate their transaction management responsibilities to transactions within the relevant platform framework provided by persistence mechanisms such as Hibernate or JTA.
The interface of the Spring Transaction Manager is org.springframework.transaction.PlatformTransaction Manager. Through this interface, Spring provides transaction managers for various platforms such as JDBC, Hibernate, etc., but the specific implementation is their own thing.
Propagation behavior of Spring's transactions: Propagation: A method in one business method that invokes another business.
There are seven types of communication provided in Spring, which can be divided into three categories:
1. Ensure that multiple operations are in the same transaction
Dissemination Behavior | Meaning |
---|---|
PROPAGATION_REQUIRED | Default value, create a new transaction if there is no transaction currently, and join a transaction if one already exists. This is the default transaction propagation behavior |
PROPAGATION_SUPPORTS | Supports the current transaction and executes non-transactionally if no transaction exists. |
PROPAGATION_MANDATORY | With the current transaction, if there is no transaction, an exception is thrown. |
2. Ensure that multiple operations are not in the same transaction:
Dissemination Behavior | Meaning |
---|---|
PROPAGATION_REQUIRES_NEW | Create a new transaction, suspend the current transaction if it exists, and create a new transaction that contains only its own operations, not those in the pending transaction. |
PROPAGATION_NOT_SUPPORTED | Perform the operation non-transactionally and suspend the current transaction if one exists. |
PROPAGATION_NEVER | Executes non-transactionally and throws an exception if a transaction currently exists. |
3. Nested transactions:
Dissemination Behavior | Meaning |
---|---|
PROPAGATION_NESTED | Nested transactions, if there are transactions in A, follow the transactions in A. After execution, set a savepoint to perform the operations in B. If there are no exceptions, execute through. If there are exceptions, you can choose to roll back to the original location or to the savepoint. |
7.2 Add Transaction
7.2.1 Programmatic Transactions
Programmatic transactions require manual coding as follows:
1. Configure Platform Transaction Manager
2. Configure template classes for transaction management
3. Inject a template for transaction management at the business tier
- TransactionTemplate does not require an explicit transaction to start or even an explicit transaction commit. These steps are done by templates.
- When an exception occurs, the transaction should be explicitly rolled back through TransactionStatus'setRollbackOnly.
- The TransactionTemplate execute method receives a TransactionCallback instance.
**Example: ** where jdbc.properties file and entity class (Account class in this example) are omitted
DAO Layer Interfaces and Implementation Classes
public interface AccountDao { //Increase Money public void addMoney(String name,Double money); //Money reduction public void minusMoney(String name,Double money); }
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { //By inheriting JdbcDaoSupport, you can get the jdbcTemplate without having to do the following because the dataSource object is defined in JdbcDaoSupport. //jdbcTemplate is also defined in the dataSource, so you only need to inject the dataSource in the JdbcDaoSupport in the configuration file /*private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }*/ @Override public void addMoney(String name, Double money) { this.getJdbcTemplate().update("update account set money=money+? where name=?",money,name); } @Override public void minusMoney(String name, Double money) { this.getJdbcTemplate().update("update account set money=money-? where name=?",money,name); } }
Service layer interfaces and implementation classes:
public interface AccountService { public void transferMoney(String from,String to,Double money); }
public class AccountServiceImpl implements AccountService { // AccountDao can also be introduced with annotations such as @Resource private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //Programmatic Transactions //Template for Injection Transaction Management private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transferMoney(String from, String to, Double money) { this.transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.minusMoney(from,money); //Throw an exception //int i=1/0; accountDao.addMoney(to,money); } }); } }
Test class:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AccountServiceTest { @Resource(name="accountService") private AccountService accountService; @Test public void test(){ accountService.transferMoney("zs","ls",2000d); } }
Configuration file applicationContext.xml
<!-- Load database configuration file --> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"/> <property name="url" value="${jdbcurl}"/> <property name="username" value="${jdbcusername}"/> <property name="password" value="${pwd}"/> </bean> <!--To configure JDBC Template--> <!--<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druid"/> </bean>--> <bean id="accountDao" class="demo1.AccountDaoImpl"> <!--Configuration here and above JDBC The template can be replaced with the next line because AccountDaoImpl Inherited from JdbcDaoSupport Defined in dataSource Object, and dataSource Is also defined in jdbcTemplate,So all you need to do is JdbcDaoSupport In dataSource Perform injection --> <!--<property name="jdbcTemplate" ref="jdbcTemplate"/>--> <property name="dataSource" ref="druid"/> </bean> <bean id="accountService" class="demo1.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> <!--Template for Business Tier Injection Transaction Management--> <property name="transactionTemplate" ref="transactionTemplate"/> </bean> <!--Programmatic Transactions--> <!--Configure Platform Transaction Manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druid"/> </bean> <!--Configure the transaction management template, where you can also configure properties such as propagation behavior, isolation level, and so on--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> </bean>
7.2.2 Declarative Transactions
Declarative transactions are built on top of AOP. The essence of declarative transactions is to intercept before and after a method, create or join a transaction before the target method starts, commit or roll back the transaction upon execution after the target method is executed. The greatest advantage of declarative transactions is that they do not need to be managed programmatically, so they do not need to be in business logic code.Doping transaction management code allows you to apply transaction rules to business logic simply by declaring relevant transaction rules in the configuration file (or by way of @Transactional annotation).
Declarative transactions can be done in two ways:
Transaction management is declared in XML:
1. Development packages that introduce aop
2. Configure Transaction Manager
3. Configuration of AOP
4. Configuration
Examples: DAO Layer, Service Layer Interface, Test Class, etc. are the same as in the above programmatic transactions, the main differences are in the configuration file and the Service Layer implementation class
<!-- configuration file --> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"/> <property name="url" value="${jdbcurl}"/> <property name="username" value="${jdbcusername}"/> <property name="password" value="${pwd}"/> </bean> <bean id="accountDao" class="demo2.AccountDaoImpl"> <property name="dataSource" ref="druid"/> </bean> <bean id="accountService" class="demo2.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean> <!--Configure Platform Transaction Manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druid"/> </bean> <!--AOP Configuration: transaction enhancements--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> <!--Define communication behavior--> </tx:attributes> </tx:advice> <!--Weave reinforcements into the appropriate method--> <aop:config> <aop:pointcut id="pointcut" expression="execution(* demo2.AccountServiceImpl.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/> </aop:config>
// Note: There is no need to add any code here. When declaring transaction management in XML, you only need to add configuration to the configuration file. public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transferMoney(String from, String to, Double money) { accountDao.minusMoney(from,money); //Throw an exception //int i=1/0; accountDao.addMoney(to,money); } }
Annotation declares transaction management:
1. Configure Transaction Manager
2. Open Annotation Transactions
3. Add notes at the business level
Example:
Annotation is done simply by configuring the Platform Transaction Manager in the configuration file and opening the annotation, then adding the annotation @Transactional ly to the class that needs to implement the transaction
<!-- configuration file --> <!--Configure Platform Transaction Manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druid"/> </bean> <!--Open Notes--> <tx:annotation-driven transaction-manager="transactionManager"/>
//Add a note to the business tier that isolation levels can be set using @Transactional(isolation =...) @Transactional public class AccountServiceImpl implements AccountService { @Resource(name = "accountDao") private AccountDao accountDao; @Override public void transferMoney(String from, String to, Double money) { accountDao.minusMoney(from,money); //Throw an exception //int i=1/0; accountDao.addMoney(to,money); } }
8. Configuration File Loading Optimization
Prevent the configuration file from being loaded once per request by creating a Spring factory, wasting server resources, and using the Spring core listener ContextLoaderListener.
When the server starts, create a Spring factory and save it in the ServletContext.
1. Introducing the jar package: spring-web
2. Configure listeners
3. Get factories directly from Action
<!-- web.xml --> <!-- Spring Core listener --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- Load Spring Configuration file path, loaded by default/WEB-INF/applicationContext.xml --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
@WebServlet("/MyServlet") public class MyServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //This method requires only one factory load ServletContext servletContext = this.getServletContext(); //Get factory, save to ServletContext when program starts WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); //Get Object UserService userService = (UserService)applicationContext.getBean("userService"); userService.save(); } }