What is spring
Spring is a lightweight open source framework for layered Java SE/EE application full stack, with IoC (Inverse Of Control) and AOP (Aspect Oriented Programming) as the kernel.
Functions of spring
In short, spring is used to manage objects. The creation, initialization, destruction and interdependent configuration of objects are handed over to the spring container, which controls the life cycle of objects.
Advantages of spring
1) Convenient decoupling and simplified development
Through the IoC container provided by Spring, the dependencies between objects can be controlled by Spring to avoid excessive coupling caused by hard coding. Users do not have to write code for the very low-level requirements such as singleton pattern class and attribute file parsing, and can focus more on the upper-level applications.
2) AOP programming support
Through the AOP function of Spring, it is convenient for aspect oriented programming. Many functions that are not easy to be realized with traditional OOP can be easily realized through AOP.
3) Declarative transaction support
It can free us from the monotonous and boring transaction management code, and carry out transaction management flexibly in a declarative way, so as to improve the development efficiency and quality.
4) Facilitate program testing
Almost all testing work can be carried out in a container independent programming way. Testing is no longer an expensive operation, but a thing to do at will.
5) Convenient integration of various excellent frameworks
Spring supports various excellent frameworks (Struts, Hibernate, Hessian, Quartz, etc.).
6) Reduce the difficulty of using Java EE API
Spring has a thin encapsulation layer for Java EE APIs (such as JDBC, JavaMail, remote calls, etc.), which greatly reduces the difficulty of using these APIs.
7) Java source code is a classic learning example
Spring's source code design is exquisite, the structure is clear, and the ingenuity is unique. It everywhere reflects the master's flexible use of Java design patterns and his profound attainments in Java technology. Its source code is not intended to be an example of best practices in Java technology.
quick get start
- Import coordinates
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jtyhnet</groupId> <artifactId>springReview1218</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> </project>
- Write interface class and implementation class
//Interface class package com.jtyhnet.dao; public interface UserDao { void save(); }
//Implementation class package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("spring test"); } }
- Create the spring core configuration file ApplicationContext XML to configure the implementation class in the configuration file
<?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"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/> </beans>
- Use Spring's API to get Bean instances
import com.jtyhnet.dao.UserDao; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class springTest { @Test public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); } }
Through in ApplicationContext Configure the corresponding class in the bean tag in XML, and use the getBean() method to obtain the object of this class for operation.
spring configuration file parsing
bean tag
Bean tag basic configuration
<bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/>
The configuration object is created by Spring.
By default, it calls the parameterless constructor in the class. If there is no parameterless constructor, it cannot be created successfully.
Basic properties:
id: the unique identifier of the Bean instance in the Spring container
class: the fully qualified name of the Bean
Scope: refers to the scope of the object. The values are as follows:
Value range | explain |
---|---|
singleton | Default, singleton |
prototype | Multiple cases |
request | In the WEB project, Spring creates a Bean object and stores the object in the request field |
session | In the WEB project, Spring creates a Bean object and stores the object in the session domain |
global session | In the WEB project, the application is in the Portlet environment. If there is no Portlet environment, the globalSession is equivalent |
The difference between singleton and prototype
Comparison content | singleton | prototype |
---|---|---|
Number of instantiations of Bean | 1 | Multiple |
Bean instantiation timing | When the Spring core file is loaded, instantiate the configured Bean instance | Instantiate the Bean when the getBean() method is called |
Bean object creation | When the application loads and creates the container, the object is created | When working with objects, create new object instances |
Bean object running | As long as the container is, the object remains alive | As long as the object is in use, it is always alive |
Bean object destruction | When the application uninstalls and destroys the container, the object is destroyed | When the object is not used for a long time, it is recycled by the Java garbage collector |
Init method: Specifies the name of the initialization method in the class
Destroy method: Specifies the name of the destroy method in the class
There are three ways to instantiate a Bean
- Parameterless construction method instantiation
It will create class objects according to the default parameterless constructor. If there is no default parameterless constructor in the bean, the creation will fail
<bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/>
- Factory static method instantiation
package com.jtyhnet.factory; import com.jtyhnet.dao.UserDao; import com.jtyhnet.dao.impl.UserDaoImpl; public class StaticFactoryBean { public static UserDao createUserDao(){ System.out.println("Static factory creation"); return new UserDaoImpl(); } }
<bean id="userDao" class="com.jtyhnet.factory.StaticFactoryBean" factory-method="createUserDao"/>
- Factory instance method instantiation
package com.jtyhnet.factory; import com.jtyhnet.dao.UserDao; import com.jtyhnet.dao.impl.UserDaoImpl; public class DynamicFactoryBean { public UserDao createUserDao(){ System.out.println("Factory instance method creation"); return new UserDaoImpl(); } }
<bean id="userDao" factory-bean="userDaoFactory" factory-method="createUserDao"/> <bean id="userDaoFactory" class="com.jtyhnet.factory.DynamicFactoryBean"/>
Dependency injection of Bean
Case:
service interface
package com.jtyhnet.service; public interface UserService { void save(); }
service implements classes and calls dao's save method in the implementation class.
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceImpl implements UserService { @Override public void save() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); } }
spring core configuration file
<?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"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"/> </beans>
Test
public void test2(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.save(); }
In the above case, both UserService instance and UserDao instance exist in the Spring container. The current practice is to obtain UserService instance and UserDao instance outside the container, and then combine them in the program.
Since both UserService and UserDao are in the Spring container, and the final program directly uses UserService, you can set UserDao inside UserService in the Spring container.
Dependency injection concept of Bean
Dependency Injection: it is the concrete implementation of the Spring framework core IOC.
When writing the program, the creation of objects is handed over to Spring through control inversion, but there can be no dependency in the code.
IOC decoupling only reduces their dependencies, but it will not eliminate them. For example, the business layer will still call the methods of the persistence layer.
After using Spring, Spring can maintain the dependency between the business layer and the persistence layer.
Simply put, it means waiting for the framework to transfer the persistence layer object to the business layer without getting it ourselves.
Dependency injection method of Bean
- set method
The instance object of which class needs to be used is set into the target class as an attribute.
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { System.out.println("set injection"); this.userDao = userDao; } @Override public void save() { userDao.save(); } }
Configure in the spring core configuration file, and inject relevant properties with the property tag inside the bean tag
<?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"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> </beans>
In addition to property tag injection, P namespace injection can also be used, but it is more convenient than the above set method injection, which is mainly reflected in the configuration file
First introduce the P namespace xmlns:p=“ http://www.springframework.org/schema/p ”, and then you can configure it on the bean tag
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl" p:userDao-ref="userDao"/> </beans>
- Construction method
The instance object of which class needs to be used is used as the parameter of the construction method
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; public class UserServiceImpl implements UserService { private final UserDao userDao; public UserServiceImpl(UserDao userDao) { System.out.println("Construction method injection"); this.userDao = userDao; } @Override public void save() { userDao.save(); } }
Use constructor Arg tag injection in the configuration file
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao"/> </bean> </beans>
The data type on which the Bean depends
Three data types of injected data
- Common data type
- Reference data type
- Collection data type
In the above case, the reference Bean is injected, that is, the reference data type
1) Common data type injection
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; public class UserDaoImpl implements UserDao { private int userId; private String userName; public void setUserId(int userId) { this.userId = userId; } public void setUserName(String userName) { this.userName = userName; } @Override public String toString() { return "UserDaoImpl{" + "userId=" + userId + ", userName='" + userName + '\'' + '}'; } @Override public void save() { System.out.println("spring test"); } }
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="userId" value="1"/> <property name="userName" value="tom"/> </bean> </beans>
public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); System.out.println(userDao); }
1) Collection data type injection
- Generic is a normal data type
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import java.util.List; public class UserDaoImpl implements UserDao { private List<String> stringList; public void setStringList(List<String> stringList) { this.stringList = stringList; } @Override public void save() { System.out.println("spring test"); System.out.println(stringList); } }
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="stringList"> <list> <value>zhangsan1</value> <value>zhangsan2</value> <value>zhangsan3</value> </list> </property> </bean> </beans>
public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); }
- Generic is a reference type
Use bean tag injection or ref tag reference inside the list tag
package com.jtyhnet.domain; public class User { private String name; private int age; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.domain.User; import java.util.List; public class UserDaoImpl implements UserDao { private List<User> userList; public void setUserList(List<User> userList) { this.userList = userList; } @Override public void save() { System.out.println("spring test"); System.out.println(userList); } }
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="userList"> <list> <bean id="user1" class="com.jtyhnet.domain.User"> <property name="name" value="tom"/> <property name="age" value="21"/> </bean> <bean id="user2" class="com.jtyhnet.domain.User"> <property name="name" value="abc"/> <property name="age" value="23"/> </bean> </list> </property> </bean> </beans>
Using ref references
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user1" class="com.jtyhnet.domain.User"> <property name="name" value="tom"/> <property name="age" value="22"/> </bean> <bean id="user2" class="com.jtyhnet.domain.User"> <property name="name" value="abc"/> <property name="age" value="23"/> </bean> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="userList"> <list> <ref bean="user1"/> <ref bean="user2"/> </list> </property> </bean> </beans>
- Map type collection injection
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.domain.User; import java.util.Map; public class UserDaoImpl implements UserDao { private Map<String,User> userMap; public void setUserMap(Map<String, User> userMap) { this.userMap = userMap; } @Override public void save() { System.out.println("spring test"); System.out.println(userMap); } }
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user1" class="com.jtyhnet.domain.User"> <property name="name" value="tom"/> <property name="age" value="22"/> </bean> <bean id="user2" class="com.jtyhnet.domain.User"> <property name="name" value="abc"/> <property name="age" value="23"/> </bean> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="userMap"> <map> <entry key="user1" value-ref="user1"/> <entry key="user2" value-ref="user2"/> </map> </property> </bean> </beans>
Key and value value types can be injected directly, and reference types can be introduced through key ref value Ref
- Properties injection
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.domain.User; import java.util.Map; import java.util.Properties; public class UserDaoImpl implements UserDao { private Properties properties; public void setProperties(Properties properties) { this.properties = properties; } @Override public void save() { System.out.println("spring test"); System.out.println(properties); } }
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="properties"> <props> <prop key="username">root</prop> <prop key="password">root</prop> </props> </property> </bean> </beans>
Introduce other configuration files (sub module development)
In actual development, there are many Spring configurations, which leads to the complexity and volume of Spring configuration. Therefore, some configurations can be disassembled into other configuration files, and loaded in the main Spring configuration file through the import tag.
<import resource="applicationContext-xxx.xml"/>
spring related API s
applicationContext: interface type, which represents the application context. Bean objects in the Spring container can be obtained through its instance
- Implementation class of ApplicationContext
- ClassPathXmlApplicationContext
It loads the configuration file from the root path of the class. This is recommended. - FileSystemXmlApplicationContext
It loads the configuration file from the disk path. The configuration file can be anywhere on the disk. - AnnotationConfigApplicationContext
When configuring container objects with annotations, you need to use this class to create a spring container. It is used to read annotations.
- The getBean() method uses
<bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"/>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao1 = (UserDao) applicationContext.getBean("userDao"); UserDao userDao2 = applicationContext.getBean("userDao", UserDao.class); UserDao userDao3 = applicationContext.getBean(UserDao.class);
In the Bean tag, id is the unique identifier in the spring container. getBean(id) can get the unique object, but it needs to be forced; Through getBean(id,class), no forced conversion is required; getBean(class) is only available when there is only one Bean of this class in the container. If there are multiple beans of the same type, it cannot be used.
spring configuration data source
Role of data source (connection pool)
• data sources (connection pools) are the key to improving program performance, such as
• instantiate the data source in advance and initialize some connection resources
• get from data source when using connection resources
• return the connected resources to the data source after use
Common data sources (connection pool): DBCP, C3P0, BoneCP, Druid, etc
Data source manual creation
Import coordinates
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency>
Create C3P0 connection pool
@Test public void testC3P0() throws PropertyVetoException, SQLException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); comboPooledDataSource.setUser("root"); comboPooledDataSource.setPassword("root"); Connection connection = comboPooledDataSource.getConnection(); System.out.println(connection); }
Create Druid connection pool
@Test public void testDruid() throws SQLException { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/test"); druidDataSource.setUsername("root"); druidDataSource.setPassword("root"); DruidPooledConnection connection = druidDataSource.getConnection(); System.out.println(connection); }
To reduce coupling, jdbc connection information is extracted into the configuration file jdbc properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root
@Test public void testC3P02() throws Exception { ResourceBundle jdbc = ResourceBundle.getBundle("jdbc"); ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(jdbc.getString("jdbc.driver")); comboPooledDataSource.setJdbcUrl(jdbc.getString("jdbc.url")); comboPooledDataSource.setUser(jdbc.getString("jdbc.username")); comboPooledDataSource.setPassword(jdbc.getString("jdbc.password")); Connection connection = comboPooledDataSource.getConnection(); System.out.println(connection); }
spring configuration data source
Analyzing the above two manually created connection pools, both are created using parameterless construction, and the set method injects configuration, so they can be created by spring.
<?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"> <bean id="c3P0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> </beans>
@Test public void test3() throws SQLException { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ComboPooledDataSource c3P0DataSource = applicationContext.getBean("c3P0DataSource", ComboPooledDataSource.class); Connection connection = c3P0DataSource.getConnection(); System.out.println(connection); System.out.println("------------------------------------"); DruidDataSource druidDataSource = applicationContext.getBean("druidDataSource", DruidDataSource.class); DruidPooledConnection connection1 = druidDataSource.getConnection(); System.out.println(connection1); }
To facilitate decoupling, use ApplicationContext The values written in XML are extracted into JDBC. XML In the properties configuration file, use the context tag in ApplicationContext Introducing jdbc.xml into XML properties.
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="jdbc.properties"/> <bean id="c3P0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans>
spring annotation development
Spring is a light code and heavy configuration framework. The configuration is heavy and affects the development efficiency. Therefore, annotation development is a trend. Annotation instead of xml configuration file can simplify the configuration and improve the development efficiency.
spring original annotation
Spring's original annotations are mainly used to replace the configuration of < bean >
annotation | explain |
---|---|
@Component | Used on classes to instantiate beans |
@Controller | Use to instantiate beans on web tier classes |
@Service | Used on the service layer class to instantiate beans |
@Repository | Used on dao layer classes to instantiate beans |
@Autowired | Use on field for type dependent injection |
@Qualifier | Used in conjunction with @ Autowired for dependency injection by name |
@Resource | Equivalent to @ Autowired+@Qualifier, injected by name |
@Value | Inject common attributes |
@Scope | Label the scope of the Bean |
@PostConstruct | Use to label the method, which is the initialization method of the Bean |
@PreDestroy | Use to mark the method as the Bean's destruction method |
When developing with annotations, you need to use the application context Component scanning is configured in XML to specify which package and beans under its sub packages need to be scanned in order to identify classes, fields and methods configured with annotations.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--Turn on component scanning--> <context:component-scan base-package="com.jtyhnet"/> </beans>
Using @ component or @ Repository to identify UserDaoImpl requires Spring to instantiate it.
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("spring anno test"); } }
@Test public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDaoImpl userDao = applicationContext.getBean("userDao", UserDaoImpl.class); userDao.save(); }
Using @ component or @ Service to identify UserServiceImpl requires Spring to instantiate it
Use @ Autowired or @ Autowired+@Qulifier or @ Resource to inject userDao
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service("userService") public class UserServiceImpl implements UserService { /*@Autowired @Qualifier("userDao")*/ @Resource(name = "userDao") private UserDao userDao; @Override public void save() { System.out.println("userService"); userDao.save(); } }
@Test public void test2(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class); userService.save(); }
Use @ Value for string injection
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl implements UserDao { @Value("Inject common data") private String str; @Value("${jdbc.driver}") private String driver; @Override public void save() { System.out.println(str); System.out.println(driver); System.out.println("spring anno test"); } }
@Test public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDaoImpl userDao = applicationContext.getBean("userDao", UserDaoImpl.class); userDao.save(); }
Use @ Scope to label the Scope of the Bean
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; @Repository("userDao") @Scope("singleton") public class UserDaoImpl implements UserDao { @Value("Inject common data") private String str; @Value("${jdbc.driver}") private String driver; @Override public void save() { System.out.println(str); System.out.println(driver); System.out.println("spring anno test"); } }
Use the @ PostConstruct annotation initialization method and the @ PreDestroy annotation destruction method
@PostConstruct public void init(){ System.out.println("init"); } @PreDestroy public void destroy(){ System.out.println("destroy"); }
spring new annotation
The above annotations cannot completely replace the xml configuration file. The configurations that need to be replaced by annotations are as follows:
Configuration of non custom beans: < Bean >
Load the configuration of the properties file: < context: Property placeholder >
Configuration of component scan: < context: component scan >
Import other files: < import >
annotation | explain |
---|---|
@Configuration | Used to specify that the current class is a Spring configuration class from which annotations will be loaded when creating a container |
@ComponentScan | Used to specify the packages that Spring will scan when initializing the container. The function is the same as < context: component scan base package = "com.jtyhnet" / > in the xml configuration file of Spring |
@Bean | On a method, annotations store the return value of the method in the Spring container |
@PropertySource | For loading Configuration in the properties file |
@Import | Used to import other configuration classes |
spring annotation configuration data source
Use @ PropertySource to import the configuration file, @ Value to inject data, and use @ Bean to store it in the spring container on the method of obtaining the data source.
package com.jtyhnet.config; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; import java.beans.PropertyVetoException; @PropertySource("classpath:jdbc.properties") public class DataSourceConfiguration { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource() throws PropertyVetoException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(driver); comboPooledDataSource.setJdbcUrl(url); comboPooledDataSource.setUser(username); comboPooledDataSource.setPassword(password); return comboPooledDataSource; } }
The spring annotation changes the xml configuration file to a configuration class
@Configuration tag this class as a configuration class
@ComponentScan configuring annotation scanning
@Import imports configuration classes of other configuration files and non custom objects (such as data source configuration classes)
package com.jtyhnet.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @ComponentScan("com.jtyhnet") @Import(DataSourceConfiguration.class) public class SpringConfiguration { }
@Test public void test3() throws SQLException { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class); UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class); userService.save(); DataSource dataSource = applicationContext.getBean("dataSource", DataSource.class); Connection connection = dataSource.getConnection(); System.out.println(connection); }
spring integration junit
step
① Import the coordinates of spring integration Junit
② Replace the original runtime with the @ Runwith annotation
③ Use @ ContextConfiguration to specify a profile or configuration class
④ Inject the object to be tested with @ Autowired
⑤ Create a test method to test
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>
import com.jtyhnet.config.SpringConfiguration; import com.jtyhnet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) //Load spring core configuration file //@ContextConfiguration(value = {"classpath:applicationContext.xml"}) //Load spring core configuration class @ContextConfiguration(classes = {SpringConfiguration.class}) public class TestSpringJunit { @Autowired private UserService userService; @Test public void test1(){ userService.save(); } }
Aspect oriented programming AOP
AOP introduction of spring
AOP is the abbreviation of Aspect Oriented Programming, which means Aspect Oriented Programming. It is a technology to realize the unified maintenance of program functions through precompiled mode and runtime dynamic agent.
AOP is the continuation of OOP, a hot spot in software development, an important content in Spring framework, and a derivative paradigm of functional programming. AOP can isolate each part of business logic, reduce the coupling between each part of business logic, improve the reusability of program, and improve the efficiency of development.
-
The role and advantages of AOP
Function: during the running of the program, enhance the function of the method without modifying the source code
Advantages: reduce duplicate code, improve development efficiency, and easy to maintain -
Underlying implementation of AOP
In fact, the underlying layer of AOP is implemented through the dynamic proxy technology provided by Spring. During operation, Spring dynamically generates proxy objects through dynamic proxy technology. When the proxy object method is executed, it intervenes to enhance the function, and calls the method of the target object, so as to complete the function enhancement. -
Common dynamic agent technology
JDK agent: dynamic agent technology based on interface
cglib proxy: dynamic proxy technology based on parent class
JDK dynamic agent
Interface class
package com.jtyhnet.JDKproxy; public interface TargetInterface { public void method(); }
Implementation class
package com.jtyhnet.JDKproxy.impl; import com.jtyhnet.JDKproxy.TargetInterface; public class TargetInterfaceImpl implements TargetInterface { @Override public void method() { System.out.println("target running"); } }
Dynamic agent
package com.jtyhnet.JDKproxy; import com.jtyhnet.JDKproxy.impl.TargetInterfaceImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class TargetProxy { public static void main(String[] args) { TargetInterfaceImpl target = new TargetInterfaceImpl(); TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Pre enhancement code"); Object invoke = method.invoke(target, args); System.out.println("Post enhancement code"); return invoke; } }); proxy.method(); } }
cglib dynamic proxy
Entity class
package com.jtyhnet.cglibProxy; public class Target { public void method(){ System.out.println("cglib proxy"); } }
Dynamic agent
package com.jtyhnet.cglibProxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxyTest { public static void main(String[] args) { //Create target object Target target = new Target(); //Create intensifier Enhancer enhancer = new Enhancer(); //Set parent class enhancer.setSuperclass(Target.class); //Set callback enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Pre enhancement cglib"); Object invoke = method.invoke(target, objects); System.out.println("Post enhancement cglib"); return invoke; } }); Target proxy = (Target) enhancer.create(); proxy.method(); } }
The bottom layer of Spring's AOP implementation is to encapsulate the code of the above dynamic agent. After encapsulation, we only need to code the parts that need attention, and complete the method enhancement of the specified goal through configuration.
Common terms of AOP are as follows:
- Target: the target object of the proxy
- Proxy: after a class is enhanced by AOP weaving, a resulting proxy class is generated
- Joinpoint s: the so-called join points refer to those intercepted points. In spring, these points refer to methods, because spring only supports method type join points
- Pointcut: the so-called pointcut refers to the definition of which joinpoints we want to intercept
- Advice (notification / enhancement): the so-called notification means that what needs to be done after intercepting the Joinpoint is notification
- Aspect: a combination of pointcuts and notifications (Introductions)
- Weaving: refers to the process of applying enhancements to the target object to create a new proxy object. spring uses dynamic proxy weaving, while AspectJ uses compile time weaving and class load time weaving
Clear matters for AOP development
- What needs to be written
- Write core business code (target method of target class)
- Write a facet class with notifications (enhancement methods) in it
- In the configuration file, configure the weaving relationship, that is, which notifications are combined with which connection points
- Content of AOP technology implementation
The Spring framework monitors the execution of pointcut methods. Once it is monitored that the pointcut method is running, the proxy mechanism is used to dynamically create the proxy object of the target object. According to the notification category, the corresponding function of the notification is woven into the corresponding position of the proxy object to complete the complete code logic operation. - Which proxy method does the underlying AOP use
In spring, the framework will decide which dynamic proxy method to adopt according to whether the target class implements the interface.
Key points of knowledge
- aop: Aspect Oriented Programming
- The underlying implementation of aop: dynamic agent based on JDK and dynamic agent based on Cglib
- Key concepts of aop:
Pointcut: enhanced method
Advice: encapsulates ways to enhance business logic
Aspect: pointcut + notification
Weaving: the process of combining pointcuts with notifications - Clear items for development:
Who is the pointcut (pointcut expression configuration)
Who is notification (enhancement method in facet class)
Weaving pointcuts and notifications into configuration
AOP development based on XML
quick get start
① Import AOP related coordinates
② Create target interface and target class (with internal tangent point)
③ Create facet class (with enhancement method inside)
④ Leave the object creation rights of the target class and the aspect class to spring
⑤ In ApplicationContext Configuring weaving relationships in XML
⑥ Test code
Coordinate import
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency>
Interface class
package com.jtyhnet.AOP; public interface TargetInterface { void method(); }
Implementation class
package com.jtyhnet.AOP.impl; import com.jtyhnet.AOP.TargetInterface; public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running"); } }
Enhanced method class
package com.jtyhnet.AOP; public class MyAspect { //Pre enhancement method public void before(){ System.out.println("Pre enhancement running"); } }
applicationContext.xml configuration file
<?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="target" class="com.jtyhnet.AOP.impl.Target"/> <bean id="myAspect" class="com.jtyhnet.AOP.MyAspect"/> <aop:config> <aop:aspect ref="myAspect"> <aop:before method="before" pointcut="execution(public void com.jtyhnet.AOP.impl.Target.method())"/> </aop:aspect> </aop:config> </beans>
test
import com.jtyhnet.AOP.TargetInterface; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.method(); } }
Detailed explanation of XML configuration AOP
Writing of tangent point expression
Expression syntax:
execution([modifier] return value type package name. Class name. Method name (parameter))
- The access modifier can be omitted
- The returned value type, package name, class name and method name can be represented by an asterisk *
- A point between the package name and the class name Represents the class under the current package, two points Represents the classes under the current package and its sub packages
- The parameter list can use two points Represents any number and any type of parameter list
Method method in target class: execution(public void com.jtyhnet.AOP.impl.Target.method())
All return value void methods in the target class: execution(void com.jtyhnet.AOP.impl.Target. * (.)
com. jtyhnet. All methods under AOP package: execution(* com.jtyhnet.AOP. *. * (.))
com. jtyhnet. All methods under the AOP package and its sub packages: execution(* com.jtyhnet.AOP. *. * (.))
All methods under the current project package and its sub packages: execution(* *. *. *. (.))
Type of notification
<aop:Notification type method="Method name in facet class" pointcut="Tangent expression"></aop:Notification type>
name | label | explain |
---|---|---|
Before advice | <aop:before> | Used to configure pre notification. Specifies that the enhanced method is executed before the pointcut method |
Post notification | <aop:after-returning> | Used to configure post notifications. Specifies that the enhanced method is executed after the pointcut method |
Around Advice | <aop:around> | Used to configure surround notifications. Specifies that the enhanced method is executed before and after the pointcut method |
Exception throw notification | <aop:throwing> | Used to configure exception throw notifications. Specifies that the enhanced method is executed when an exception occurs |
Final notice | <aop:after> | Used to configure final notifications. The enhanced mode will be executed regardless of whether there are exceptions |
Tangent expression extraction
When multiple enhanced pointcut expressions are the same, the pointcut expression can be extracted. In the enhancement, the pointcut ref attribute is used instead of the pointcut attribute to reference the extracted pointcut expression.
<aop:config> <aop:aspect ref="myAspect"> <aop:pointcut id="targetPointcut" expression="execution(public void com.jtyhnet.AOP.impl.Target.method())"/> <aop:before method="before" pointcut-ref="targetPointcut"/> </aop:aspect> </aop:config>
main points
aop weaving configuration
<aop:config> <aop:aspect ref="Section class"> <aop:before method="Notification method name" pointcut="Tangent expression"></aop:before> </aop:aspect> </aop:config>
Notification types: pre notification, post notification, surround notification, exception throw notification, and final notification
How to write tangent point expression:
execution([modifier] return value type package name. Class name. Method name (parameter))
Annotation based AOP development
quick get start
Annotation based aop development steps:
① Create target interface and target class (with internal tangent point)
② Create facet class (with enhancement method inside)
③ Leave the object creation rights of the target class and the aspect class to spring
④ Using annotations to configure weaving relationships in facet classes
⑤ Turn on the automatic agent for component scanning and AOP in the configuration file
⑥ Testing
Interface class
package com.jtyhnet.AOPanno.impl; public interface TargetInterface { void method(); }
The implementation class @ Component is handed over to spring for management
package com.jtyhnet.AOPanno; import com.jtyhnet.AOPanno.impl.TargetInterface; import org.springframework.stereotype.Component; @Component("target") public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running"); } }
Configure weaving in section class
package com.jtyhnet.AOPanno; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component("myAspect") @Aspect public class MyAspect { //Pre enhancement method @Before("execution(* com.jtyhnet.AOPanno.*.*(..))") public void before(){ System.out.println("Pre enhancement running"); } }
Enable annotation scanning and AOP automatic agent in configuration file
<?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="com.jtyhnet.AOPanno"/> <aop:aspectj-autoproxy/> </beans>
import com.jtyhnet.AOPanno.impl.TargetInterface; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.method(); } }
Annotation configuration AOP details
Type of annotation notification
Configuration syntax of notification: @ notification annotation ("pointcut expression")
name | annotation | explain |
---|---|---|
Before advice | @Before | Used to configure pre notification. Specifies that the enhanced method is executed before the pointcut method |
Post notification | @AfterReturning | Used to configure post notifications. Specifies that the enhanced method is executed after the pointcut method |
Around Advice | @Around | Used to configure surround notifications. Specifies that the enhanced method is executed before and after the pointcut method |
Exception throw notification | @AfterThrowing | Used to configure exception throw notifications. Specifies that the enhanced method is executed when an exception occurs |
Final notice | @After | Used to configure final notifications. The enhanced mode will be executed regardless of whether there are exceptions |
Extraction of tangent expression
Like configuring aop with xml, we can extract Pointcut expressions. The extraction method is to define a method in the cut plane, define the cut point expression on the method with the @ Pointcut annotation, and then refer to it in the enhanced annotation. The details are as follows:
package com.jtyhnet.AOPanno; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component("myAspect") @Aspect public class MyAspect { //Pre enhancement method @Before("MyAspect.myPoint()") public void before(){ System.out.println("Pre enhancement running"); } @Pointcut("execution(* com.jtyhnet.AOPanno.*.*(..))") public void myPoint(){} }
Annotate aop development steps
① Dimension facet classes with @ Aspect
② Annotate notification method with @ notification annotation
③ Configure aop auto proxy in the configuration file < aop: AspectJ AutoProxy / >
Spring JdbcTemplate basic usage
JdbcTemplate overview
It is an object provided in the spring framework and a simple encapsulation of the original cumbersome Jdbc API object. The spring framework provides us with many operation template classes. For example: JdbcTemplate and HibernateTemplate for operating relational data, RedisTemplate for operating nosql database, JmsTemplate for operating message queue, etc.
JdbcTemplate development steps
① Import spring JDBC and spring TX coordinates
② Create database tables and entities
③ Create a JdbcTemplate object
④ Perform database operations
<!--Import spring of jdbc coordinate--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <!--Import spring of tx coordinate--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version> </dependency>
//1. Create data source object ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUser("root"); dataSource.setPassword("root"); //2. Create a JdbcTemplate object JdbcTemplate jdbcTemplate = new JdbcTemplate(); //3. Set data source to JdbcTemplate jdbcTemplate.setDataSource(dataSource); //4. Perform operation jdbcTemplate.update("insert into account values(?,?)","tom",5000);
Spring configuration JdbcTemplate object
<!--data source DataSource--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///test"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!--JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
@Test public void testSpringJdbcTemplate() throws PropertyVetoException { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); JdbcTemplate jdbcTemplate = applicationContext.getBean(JdbcTemplate.class); //insert data jdbcTemplate.update("insert into account values(?,?)","lucy",5000); //Update data jdbcTemplate.update("update account set money=? where name=?",1000,"tom"); //Query data and return result set List<Account> accounts = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class)); for (Account account : accounts) { System.out.println(account.getName()); } //Query a single object Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), "tom"); System.out.println(account.getName()); }
Declarative transaction control
Programming transaction control related objects
- The PlatformTransactionManager interface is the transaction manager of spring, which provides our common methods of operating transactions.
method | explain |
---|---|
TransactionStatus getTransaction(TransactionDefination defination) | Gets the status information of the transaction |
void commit(TransactionStatus status) | Commit transaction |
void rollback(TransactionStatus status) | Rollback transaction |
be careful:
PlatformTransactionManager is an interface type, and different Dao layer technologies have different implementation classes,
For example: when Dao layer technology is JDBC or mybatis: org springframework. jdbc. datasource. DataSourceTransactionManager
When Dao layer technology is Hibernate: org springframework. orm. hibernate5. HibernateTransactionManager
- TransactionDefinition is the transaction definition information object, which contains the following methods:
method | explain |
---|---|
int getIsolationLevel() | Gets the isolation level of the transaction |
int getPropogationBehavior() | Get propagation behavior of transaction |
int getTimeout() | Get timeout |
boolean isReadOnly() | Read only |
- Transaction isolation level
Setting the isolation level can solve the problems caused by transaction concurrency, such as dirty read, non repeatable read and virtual read.
level | explain |
---|---|
ISOLATION_DEFAULT | Use the default isolation level of the back-end database |
ISOLATION_READ_UNCOMMITTED | Allow reading of uncommitted changes. It may cause dirty reading, unreal reading or non repeatable reading. |
ISOLATION_READ_COMMITTED | The read has been committed to ensure that the modified data of one transaction can be read by another transaction only after it is committed |
ISOLATION_REPEATABLE_READ | It can be read repeatedly to ensure that dirty reading does not occur. It can not be read repeatedly, but phantom reading will occur, |
ISOLATION_SERIALIZABLE | Transactions are processed in sequence and completely obey the isolation level of ACID to ensure that dirty reads, unrepeatable reads and phantom reads do not occur. |
- Transaction propagation behavior
REQUIRED: if there is no transaction currently, create a new transaction. If there is already a transaction, join it. General selection (default)
SUPPORTS: SUPPORTS the current transaction. If there is no transaction, it will be executed in a non transactional manner (no transaction)
MANDATORY: use the current transaction. If there is no transaction, an exception will be thrown
REQUERS_NEW: create a new transaction. If it is currently in a transaction, suspend the current transaction.
NOT_SUPPORTED: perform operations in a non transactional manner. If there is a transaction, suspend the current transaction
NEVER: runs in a non transactional manner. If there is a transaction, an exception will be thrown
NESTED: if a transaction currently exists, it is executed within a NESTED transaction. If there is no current transaction, perform an operation similar to REQUIRED
Timeout: the default value is - 1. There is no timeout limit. If yes, set in seconds
Read only: it is recommended to set it as read-only when querying
- The TransactionStatus interface provides the specific running status of transactions. The methods are described below.
method | explain |
---|---|
boolean hasSavepoint() | Store rollback points |
boolean isCompleted() | Is the transaction complete |
boolean isNewTransaction() | Is this a new transaction |
boolean isRollbackOnly() | Whether the transaction is rolled back |
Declarative transaction control based on XML
Spring's declarative transaction, as its name implies, is to handle transactions in a declarative manner. The declaration here refers to the declaration in the configuration file, and the declarative transaction in the spring configuration file is used to replace the code transaction.
- The role of declarative transactions
- Transaction management does not invade developed components. Specifically, the business logic object will not realize that it is in the process of transaction management. In fact, it should be the same, because transaction management is a system level service, not a part of business logic. If you want to change the transaction management plan, you only need to reconfigure it in the definition file
- When transaction management is not required, the transaction management service can be removed by modifying the setting file without changing the code and recompiling, which is extremely convenient for maintenance
The underlying layer of Spring declarative transaction control is AOP.
Declarative transaction control matters:
who is the tangent point?
who is the notice?
configuration section?
Implementation of declarative transaction control
Transfer case:
Dependent coordinates
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version> </dependency>
dao interface class
package com.jtyhnet.dao; public interface UserDao { void in(String inMan,double money); void out(String outMan,double money); }
dao implementation class
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import org.springframework.jdbc.core.JdbcTemplate; public class UserDaoImpl implements UserDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void in(String inMan, double money) { System.out.println(inMan+" to change into "+money); jdbcTemplate.update("update account set money=money+? where name = ?",money,inMan); } @Override public void out(String outMan, double money) { System.out.println(outMan+" Transfer out "+money); jdbcTemplate.update("update account set money=money-? where name = ?",money,outMan); } }
service interface class
package com.jtyhnet.service; public interface UserService { void transfer(String outMan,String inMan,Double money); }
service implementation class
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void transfer(String outMan,String inMan,Double money) { userDao.out(outMan,money); userDao.in(inMan,money); } }
applicationContext.xml configuration file
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> </beans>
New account table for test
create table account( id INT NOT NULL auto_increment, name VARCHAR ( 255 ) , money decimal(20,2), PRIMARY KEY ( id ) ); insert into account values (null,'zhangsan',5000); insert into account values (null,'lisi',5000);
Test transfer function
import com.jtyhnet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestSpringTx { @Autowired private UserService userService; @Test public void test1(){ userService.transfer("zhangsan","lisi",100.0); } }
Query database transfer succeeded
According to the logic of transaction control, the transfer out and transfer in should be within one transaction. If the transfer out and transfer in is abnormal, the whole transaction will fail and the money of the two users will not change.
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void transfer(String outMan,String inMan,Double money) { userDao.out(outMan,money); int i = 1/0; userDao.in(inMan,money); } }
Use int i = 1/0; Simulate abnormal test
It is found that although an error is reported, the transfer out operation is still completed and the transfer in fails. It is necessary to configure a transaction for the transfer out and transfer in.
1. Introduce tx namespace into XML
2. Configure the bean of the transactionManager and inject the dataSource into the dataSource
3.tx:advice configuration transaction enhancement,
Use < TX: attributes >
<tx:method name="*"/>
</tx:attributes>
Specify the method to enhance
4. To combine transaction control with business logic code, aop weaving is used to realize transaction enhancement
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!--Platform transaction manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--Transaction enhanced configuration--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice> <!--Configure transactions AOP Weave in--> <aop:config> <aop:pointcut id="myPointcut" expression="execution(* com.jtyhnet.service.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/> </aop:config> </beans>
Test again after restoring the data in the table
Achieve overall control
-
The difference between < AOP: aspect > and < AOP: advisor >
< AOP: advisor > is mostly used for transaction management< AOP: aspect > is used for common aspects, such as logs
< AOP: advisor > advice needs to be configured and injected< AOP: aspect > acts on specific bean s -
Configuration of transaction parameters of pointcut method
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice>
Where, < TX: method > represents the configuration of the transaction parameters of the pointcut method, for example:
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
Name: tangent point method name
Isolation: isolation level of transaction
Propagation: propagation behavior of transactions
Timeout: timeout
Read only: read only
Annotation based declarative transaction control
First change the case to annotation development, and then add transaction control after verifying that the transfer function is successful
The reference XML configuration is gradually changed to annotation
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDao" class="com.jtyhnet.dao.impl.UserDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="userService" class="com.jtyhnet.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!--Platform transaction manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--Transaction enhanced configuration--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice> <!--Configure transactions AOP Weave in--> <aop:config> <aop:pointcut id="myPointcut" expression="execution(* com.jtyhnet.service.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/> </aop:config> </beans>
- Annotation configuration dataSource
package com.jtyhnet.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; import java.beans.PropertyVetoException; @PropertySource("classpath:jdbc.properties") public class C3P0DataSource { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource() throws PropertyVetoException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(driver); comboPooledDataSource.setJdbcUrl(url); comboPooledDataSource.setUser(username); comboPooledDataSource.setPassword(password); return comboPooledDataSource; } }
- Annotation configuration JdbcTemplate
package com.jtyhnet.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; import javax.annotation.Resource; import javax.sql.DataSource; public class Day05JdbcTemplate { @Autowired private DataSource dataSource; @Bean("jdbcTemplate") public JdbcTemplate getJdbcTemplate(){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
- Configure spring core configuration classes
package com.jtyhnet.config; import com.jtyhnet.DataSource.C3P0DataSource; import com.jtyhnet.DataSource.Day05JdbcTemplate; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @ComponentScan("com.jtyhnet") @Import({C3P0DataSource.class, Day05JdbcTemplate.class}) public class SpringConfiguration { }
Since neither DataSource nor JdbcTemplate is a custom class, use @ Import to Import
- Configure dao,service
package com.jtyhnet.dao; public interface UserDao { void in(String inMan,double money); void out(String outMan,double money); }
package com.jtyhnet.dao.impl; import com.jtyhnet.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void in(String inMan, double money) { System.out.println("anno " + inMan+" to change into "+money); jdbcTemplate.update("update account set money=money+? where name = ?",money,inMan); } @Override public void out(String outMan, double money) { System.out.println("anno " + outMan+" Transfer out "+money); jdbcTemplate.update("update account set money=money-? where name = ?",money,outMan); } }
package com.jtyhnet.service; public interface UserService { void transfer(String outMan,String inMan,Double money); }
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void transfer(String outMan, String inMan, Double money) { userDao.out(outMan,money); userDao.in(inMan,money); } }
- test
import com.jtyhnet.config.SpringConfiguration; import com.jtyhnet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class SpringTest { @Autowired private UserService userService; @Test public void test1(){ userService.transfer("zhangsan","lisi",100.0); } }
Query database transfer succeeded
Add annotation to configure declarative transaction control:
① Use @ Transactional to modify classes or methods that need transaction control. The attributes available for annotation are the same as xml configuration methods, such as isolation level, propagation behavior, etc.
② If annotations are used on a class, all methods under the class are configured with the same set of annotation parameters.
③ In terms of methods, different methods can adopt different transaction parameter configurations.
④ Annotation driven to enable transaction in Xml configuration file < TX: annotation driven / >
package com.jtyhnet.service.impl; import com.jtyhnet.dao.UserDao; import com.jtyhnet.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service("userService") @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; //@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED) @Override public void transfer(String outMan, String inMan, Double money) { userDao.out(outMan,money); int i = 1/0; userDao.in(inMan,money); } }
xml configuration
< TX: annotation driven transaction manager = "transactionManager" / >, where transaction manager = "transactionManager" can be omitted. By default, < TX: annotation driven > will automatically use the transaction manager named transactionManager.
<?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:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.jtyhnet"/> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!--Platform transaction manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--Annotation driven transactions--> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
test
import com.jtyhnet.config.SpringConfiguration; import com.jtyhnet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringTest { @Autowired private UserService userService; @Test public void test1(){ userService.transfer("zhangsan","lisi",100.0); } }
Query the database to confirm that both transfer out and transfer in failed, and the transaction was controlled
In order to make @ Transactional effective, the above annotation development still uses the xml configuration file, and the annotation transformation is not complete. After analysis, it is found that
<!--Platform transaction manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
In fact, it is also a configuration class. Therefore, you can refer to the data source configuration class and write a separate transaction manager configuration class. It is introduced in the spring core configuration class @ import, and use the @ EnableTransactionManagement tag instead of < TX: annotation driven / >
Transaction manager configuration class
package com.jtyhnet.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; public class Day05TransactionManager { @Autowired private DataSource dataSource; @Bean("transactionManager") public DataSourceTransactionManager getDataSourceTransactionManager(){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }
spring core configuration class
package com.jtyhnet.config; import com.jtyhnet.DataSource.C3P0DataSource; import com.jtyhnet.DataSource.Day05JdbcTemplate; import com.jtyhnet.DataSource.Day05TransactionManager; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @ComponentScan("com.jtyhnet") @Import({C3P0DataSource.class, Day05JdbcTemplate.class, Day05TransactionManager.class}) @EnableTransactionManagement public class SpringConfiguration { }
test
import com.jtyhnet.config.SpringConfiguration; import com.jtyhnet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class SpringTest { @Autowired private UserService userService; @Test public void test1(){ userService.transfer("zhangsan","lisi",100.0); } }
Transactions under control