Spring Use Details

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

  1. 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
  2. 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&amp;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&amp;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&amp;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 BehaviorMeaning
PROPAGATION_REQUIREDDefault 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_SUPPORTSSupports the current transaction and executes non-transactionally if no transaction exists.
PROPAGATION_MANDATORYWith the current transaction, if there is no transaction, an exception is thrown.

2. Ensure that multiple operations are not in the same transaction:

Dissemination BehaviorMeaning
PROPAGATION_REQUIRES_NEWCreate 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_SUPPORTEDPerform the operation non-transactionally and suspend the current transaction if one exists.
PROPAGATION_NEVERExecutes non-transactionally and throws an exception if a transaction currently exists.

3. Nested transactions:

Dissemination BehaviorMeaning
PROPAGATION_NESTEDNested 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();
    }
}

Tags: Java Spring

Posted on Sat, 16 Oct 2021 14:23:44 -0400 by Nukedesign