Spring - third day of study (IOC at the core of Spring)

Keywords: Spring xml Java Programming

Spring Day 3

Introduction to AOP

What is AOP?

AOP (full name: Aspect Oriented Programming) is Face-Oriented Programming. It is the continuation of OOP, which is also called Spring as the two core of IOC.In Spring, it is mainly used to isolate parts of business logic, which reduces the coupling between parts of business logic, improves the reusability of programs, and greatly improves the efficiency of development.

The Role and Advantage of AOP

Effect

Enhance existing methods, that is, use dynamic proxies, without modifying the source code while the program is running.

advantage

  • Reduce duplicate code
  • Improving development efficiency
  • Easy maintenance

Introducing learning cases - adding transaction support to the business tier

Business tier code

package com.gzgs.service.impl;

import com.gzgs.dao.AccountDao;
import com.gzgs.domain.Account;
import com.gzgs.service.AccountService;

import java.util.List;

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public List<Account> findAll() {
        return accountDao.findAll();
    }

    public Account findAccountById(int id) {
        return accountDao.findAccountById(id);
    }

    public void insertAccount(Account account) {
        accountDao.insertAccount(account);
    }

    public void deleteAccount(int id) {
        accountDao.deleteAccount(id);
    }

    public void updateAccount(int id, Account account) {
        accountDao.updateAccount(id,account);
    }

    public void transfer(String sourceName, String targetName, double money) {
        //Query outgoing accounts
        Account source = accountDao.findAccountByName(sourceName);
        //Query Transfer Account
        Account target=accountDao.findAccountByName(targetName);
        //Transfer account deduction
        source.setMoney(source.getMoney()-money);
        //Transfer to account to add money
        target.setMoney(target.getMoney()+money);
        //Update outgoing accounts
        accountDao.updateAccount(source.getId(),source);

        //Update Transferred Account
        accountDao.updateAccount(target.getId(),target);
    }
}

Proxy Object Factory Code

package com.gzgs.factory;

import com.gzgs.service.AccountService;
import com.gzgs.utils.TransactionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * A proxy object factory for creating a Service
 */
public class BeanFactory {
   private AccountService accountService;
   private TransactionManager txManager;

    public void setAccountService(AccountService accountService) {
        this.accountService = accountService;
    }

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }

    public AccountService getAccountService(){
        return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object rtValue=null;
                        try {
                            //Open Transaction
                            txManager.beginTransaction();
                            //Perform operation
                            rtValue = method.invoke(accountService, args);
                            //Submit Transaction
                            txManager.commit();
                            //Return results
                            return rtValue;
                        }catch (Exception e){
                            txManager.rollback();
                            throw new RuntimeException(e);
                        }finally {
                            //Release Connection
                            txManager.release();
                        }
                    }
                });
    }
}

Terminology related to AOP

Joinpoint

Connection points are those that are intercepted.In spring, these points refer to methods, because spring only supports method types
Connection points, for example, are all methods in AccountServiceImpl.

Pointcut (entry point)

The starting point is the definition of which Joinpoint s we want to intercept, which is the way we need to enhance them.Conceptually, all entry points are connection points, and connection points are not necessarily entry points.

Advice (Notification/Enhancement)

Notification means that what you do after intercepting a Joinpoint is notification.
The types of notifications: pre-notification, post-notification, exception notification, final notification, surround notification, depending on the location relative to the entry point.

Introduction (Introduction)

Introduction s are special notifications that dynamically add parties to a class at run time without modifying its class code
Method or Field.

Target (Target Object)

The target object of the proxy, AccountServiceImpl in the example above.

Weaving

This 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-loading weaving.

Proxy (proxy)

When a class is enhanced by AOP weaving, a result proxy class is produced, which is the return result of getAccountService in the example above.

Aspect

Is the combination of entry point and notification (introductory)

What you need to be clear about learning AOP in spring

Development phase (what we do)

Write core business code (main line of development): Most programmers do this, requiring familiarity with business needs.

Pull out the common code and make a notification.(Do it last in the development phase): AOP programmers do it.

In the configuration file, declare the relationship between the entry point and the notification, that is, the facet.: AOP programmers do it.

Runtime (completed by the Spring framework)

The Spring framework monitors the execution of entry point methods.Once the monitoring to entry point method is run, the agent mechanism is used to dynamically create the agent object of the target object, according to the notification category, in the corresponding location of the agent object, the corresponding function of the notification is organized to complete the complete code logic operation.

In spring, the framework decides which dynamic proxy method to use based on whether the target class implements an interface or not.

XML-based AOP configuration (improves transaction control transfer cases above)

bean.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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--To configure AccountService-->
    <bean id="accountService" class="com.gzgs.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!--To configure AccountDaoImpl object-->
    <bean id="accountDao" class="com.gzgs.dao.impl.AccountDaoImpl">
        <property name="runner" ref="runner"></property>
        <!-- injection ConnectionUtils -->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
    <!--To configure QuueryRunner object-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test02"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
    <!-- To configure Connection Tool class ConnectionUtils -->
    <bean id="connectionUtils" class="com.gzgs.utils.ConnectionUtils">
        <!-- Injection Data Source-->
       <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- Configure Transaction Manager-->
    <bean id="txManager" class="com.gzgs.utils.TransactionManager">
        <!-- injection ConnectionUtils -->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>


    <!--To configure AOP-->
    <aop:config>
        <!-- Configure entry point expressions id Property specifies the unique identity of the expression. expression Property is used to specify expression content
              This label is written in aop:aspect Inside the label can only be used for the current cut.
              It can also be written in aop:aspect Outside, now all facets are available
          -->
        <aop:pointcut id="pt1" expression="execution(* com.gzgs.service.impl.*.*(..))"></aop:pointcut>
        <!--Configure Faces-->
        <aop:aspect id="advice" ref="txManager">
            <!--Configure Pre-Notification-->
            <aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before>
            <!--Configure Post Notification-->
            <aop:after-returning method="commit" pointcut-ref="pt1"></aop:after-returning>
            <!--Configure exception notifications-->
            <aop:after-throwing method="rollback" pointcut-ref="pt1"></aop:after-throwing>
            <!--Configure Final Notification-->
            <aop:after method="release" pointcut-ref="pt1"></aop:after>


        </aop:aspect>
    </aop:config>



</beans>

Annotation-based AOP configuration (improves transaction control transfer cases above)

When using annotation-based AOP configurations, there is often a bug in the post-notification execution exception, which is caused by the inconsistency of the calling order of the four notifications: pre-notification, final notification, and post-notification.This results in a post-notification execution failure because the resource is freed, usually with an error message that connection autocommit is not set to false because it is no longer connected to the pre-notification.So when using annotation-based AOP configurations, it is best to use surround notifications to control the order in which programs are executed.

Core AOP Code

package com.gzgs.utils;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Tool class related to transaction management that includes, opening transactions, committing transactions, rolling back transactions, and releasing connections
 */
@Component("transactionManager")
@Aspect
public class TransactionManager {
    @Autowired
    private ConnectionUtils connectionUtils;

    @Pointcut("execution(* com.gzgs.service.impl.*.*(..))")
    private void pt1(){}


    /**
     * Open Transaction
     */

    public  void beginTransaction(){
        try {
            System.out.println("I'm front");
            connectionUtils.getThreadConnection().setAutoCommit(false);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Submit Transaction
     */

    public  void commit(){
        try {

            connectionUtils.getThreadConnection().commit();

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Rollback transaction
     */

    public  void rollback(){
        try {
            System.out.println("I am an exception");
            connectionUtils.getThreadConnection().rollback();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * Release Connection
     */



    public  void release(){
        try {
            System.out.println("release");
            connectionUtils.getThreadConnection().close();//Return to Connection Pool
            connectionUtils.removeConnection();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Around("pt1()")
    public Object aroundAdvice(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try {
            //1. Get parameters
            Object[] args = pjp.getArgs();
            //2. Open Transactions
            this.beginTransaction();
            //3. Execution Method
            rtValue = pjp.proceed(args);
            //4. Submit Transaction
            this.commit();
            System.out.println("I'm rear");
            //Return results
            return  rtValue;

        }catch (Throwable e){
            //5. Roll back the transaction
            this.rollback();
            throw new RuntimeException(e);
        }finally {
            //6. Release resources
            this.release();
        }
    }
}

Learning Code:https://download.csdn.net/download/weixin_45680962/12550122
This blog is purely a personal learning note. The learning resources are from the Black Horse Training Camp. If there are any errors, please correct them.

Posted by dominod on Wed, 24 Jun 2020 19:09:26 -0700