Day5 Spring AOP

Spring AOP

AOP related terms

Spring AOP is an enhancement to the method.

  • A connection point (the JoinPoint)
    Method

  • Entry point (Pointcut)
    determine which methods need to strengthen

  • Notification (Advice)
    which stage method of operation, at the beginning of the end, return, abnormal, + the beginning of the end?
    Did what enhancements, add logs, transactions, load balancing?

  • Section (Aspect)
    where what had been done to enhance that section = + entry point notification

Aspect Oriented Programming What to do?
What kind of method in which, when run in the way of doing what enhancements;

In what class which methods = entry point (Pointcut)
run to the method in which reinforced what time do + = notice (Advice)

Instructions

Based Interface

Spring AOP is the first completely done several interfaces.

advice

Spring AOP is the first completely done several interfaces.

  1. By implementing AfterReturningAdvicethe interface, define a rear notification (operation after the end of the proxy method, the notification is called);
public class LogAdvice implements AfterReturningAdvice {

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(dateFormat.format(new Date()) + ": method " + method.getName() + " invoked.");
    }
}
  1. Xml configuration file
    focus is to configure the proxy factory: ProxyFactoryBean
    <!--被代理bean-->
    <bean id="userService" class="com.bailiban.day4.aop.dynamic_proxy.noproxy.UserServiceImpl" />

    <!--  代理通知bean  -->
    <bean id="logAdvice" class="com.bailiban.day4.aop.spring12.LogAdvice" />

    <!--  代理工厂bean  -->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--        被代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.bailiban.day4.aop.dynamic_proxy.noproxy.UserService</value>
            </list>
        </property>
<!--        被代理bean-->
        <property name="target" ref="userService"/>
<!--        通知-->
        <property name="interceptorNames">
            <list>
                <value>logAdvice</value>
            </list>
        </property>
    </bean>

As can be seen from userServiceProxy configuration, which is configured with a manual written based on JDK dynamic proxy is very similar, all three aspects of the design:

  • The proxy interface: UserService
  • The proxy class: UserServiceImpl
  • Enhancement: logAdvice

test:

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "com/bailiban/day4/aop/spring12/advice.xml");
        UserService userService = (UserService) context.getBean("userServiceProxy");
        userService.getUser();
        userService.createUser();
        userService.updateUser();
        userService.deleteUser();
    }

Write dynamic proxy code consistent with the results of the manual:

getUser
2019-12-22 14:50:20: method getUser invoked.
createUser
2019-12-22 14:50:20: method createUser invoked.
updateUser
2019-12-22 14:50:20: method updateUser invoked.
deleteUser
2019-12-22 14:50:20: method deleteUser invoked.

Based interface may also have other, more complex configurations, to provide a richer AOP programming. But now rarely used based interface written in Spring AOP, skip this.
Other uses may reference code: https: //github.com/Jun67/spring-demo/tree/master/src/main/java/com/bailiban/day4/aop/spring12

advisor

advice default all methods to make enhancements to the designated proxy object, use the advisor can further specify which methods enhanced.

  1. A new advisor bean
<!--    在匹配(按方法名)的方法上通知-->
    <bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--        1. 通知做哪些事情-->
        <property name="advice" ref="logAdvice" />
<!--        2. 指定哪些方法-->
        <property name="mappedNames" value="getUser" />
    </bean>
  1. Modify ProxyFactoryBean interceptor configuration, adding an advisor
<!--    动态代理-->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--        指定接口-->
        <property name="proxyInterfaces" value="com.bailiban.day5.aop.noproxy.UserService" />
<!--        指定代理对象-->
        <property name="target" ref="userService" />
<!--        指定增强的方法 -->
        <property name="interceptorNames">
            <list>
<!--                <value>beforeAdvice</value>-->
<!--                <value>logAdvice</value>-->
<!--                加入新增的advisor,用于控制指定方法做增强处理-->
                <value>advisor</value>
            </list>
        </property>
    </bean>
  1. test
    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "com/bailiban/day5/aop/springaop/bean/advisor/advisor.xml");
        UserService userService = (UserService) context.getBean("userServiceProxy");
        userService.createUser();
        userService.deleteUser();
        userService.updateUser();
        userService.getUser();
    }
  1. operation result
创建了一个新用户。
删除一个用户。
更新一个用户。
查找一个用户。
2019-12-25 09:02:55: method getUser invoked.
autoProxyCreator

advice and advisor, when using a proxy bean, we need to get the original bean name (userService) through a proxy bean (userServiceProxy).

It may be generated from the constant autoProxyCreator proxy class. In use, direct access to the original bean name (userService) to obtain the proxy object.

  1. It creates a new proxy bean
    <!--    动态代理,自动生成代理对象-->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--       按bean的名称来进行代理,以Service结尾的bean都会被代理-->
        <property name="beanNames" value="*Service" />
        <!--        指定增强的方法 -->
        <property name="interceptorNames">
            <list>
                <!--   advisor,用于控制指定方法做增强处理-->
                <value>advisor</value>
            </list>
        </property>
    </bean>
  1. test
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "com/bailiban/day4/aop/spring12/autoproxy/autoproxy.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.getUser();
        userService.createUser();
        userService.updateUser();
        userService.deleteUser();
    }

result:

getUser
2019-12-25 17:55:43: method getUser invoked.
createUser
2019-12-25 17:55:43: method createUser invoked.
updateUser
deleteUser
DafaultAdvisor..

You can not fail to configure the proxy bean properties? That method does not specify which what has been done to enhance?

The userServiceProxy replaced by a type of bean can DefaultAdvisorAutoProxyCreator

<!--    动态代理,自动生成代理对象-->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
Based aop label

Spring 2.0 onwards, provided Two kinds of annotations and labels @Aspectj AOP programming.

Need to add the following dependency in pom.xml:

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
A simple example

Example of use:

    <!--被代理bean-->
    <bean id="userService" class="com.bailiban.day4.aop.dynamic_proxy.noproxy.UserServiceImpl" />

    <!--  代理通知bean  -->
    <bean id="logAdvice" class="com.bailiban.day4.aop.aopxml.LogAdvice" />
<!--    环绕切口-->
    <bean id="aroundAdvice" class="com.bailiban.day4.aop.aopxml.AroundAdvice" />

<!--    aop相关配置-->
    <aop:config>
<!--        定义切面,该切面的增强方法在logAdvice中定义的-->
        <aop:aspect ref="logAdvice">
<!--            指定在哪些类的哪些方法代理
        execution(* com.bailiban.day5.aop.noproxy.UserServiceImpl.*(..))
        execution:指定方法签名;
        *:表示任意字符,第一个* 表示方法的限定符(private,public),此处表示任意;
        com.bailiban.day5.aop.noproxy.UserServiceImpl:指定类名;
        第二个* :表示任意方法,即UserServiceImpl类下面的所有方法;
        (..):指定参数,此处使用..表示任意参数。注意".."也可以用来表示任意子包。
-->          
            <aop:pointcut id="log" expression="execution(* com..noproxy.UserServiceImpl.*(..))"/>
<!--            指定在代理方法运行结束之后,执行增强方法-->          
            <aop:after method="logger" pointcut-ref="log" />
        </aop:aspect>
      
<!--        定义切面,该切面的增强方法在aroundAdvice中定义的-->
        <aop:aspect ref="aroundAdvice">
            <aop:pointcut id="arround" expression="execution(* com..noproxy.UserServiceImpl.*(..))"/>
            <aop:around method="around" pointcut-ref="arround" />
        </aop:aspect>
    </aop:config>

key point:

  1. <aop:config>: Indicates that this is a aop configuration;
  2. <aop:aspect ref="logAdvice">
    Section configuration, ref used for the notification section (i.e., enhanced code)
  3. <aop:pointcut>: Configuration entry point
    is important:expression="execution(* com..noproxy.UserServiceImpl.*(..))"
    specify where to be cut, that is, which method will be enhanced. The above expression means that all methods will UserServiceImpl class is enhanced.
  4. <aop:around>: Specifies the cut time, here is the surround, ie before and after the proxy method will be enhanced.
    Other entry points:
  • <aop:before>: Before running the method;
  • <aop:after>: Method to finish, but no return value;
  • <aop:after-returning>: The method of operation ends, and the return value can be obtained;
  • <aop:after-throwing>: Cut the exception;

test:

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "com/bailiban/day4/aop/aopxml/aop.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.getUser();
        userService.createUser();
        userService.updateUser();
        userService.deleteUser();
    }

operation result:

开始执行...
getUser
结束执行...
2019-12-23 21:58:14: method getUser invoked.
开始执行...
createUser
结束执行...
2019-12-23 21:58:14: method createUser invoked.
开始执行...
updateUser
结束执行...
2019-12-23 21:58:14: method updateUser invoked.
开始执行...
deleteUser
结束执行...
2019-12-23 21:58:14: method deleteUser invoked.
Example: Transaction

Handwriting Services

  1. Write a query function;
package com.bailiban.day5.aop.springaop.aop.transfer;

import java.sql.*;

public class JdbcUtil {

    private static String jdbcUrl = "jdbc:mysql://192.168.1.132:3306/spring_demo?serverTimezone=Asia/Shanghai";
    private static String username = "root";
    private static String password = "root";
    private static String driver = "com.mysql.jdbc.Driver";

    public static void main(String[] args) {

        // 1. Class.forName,加载用于mysql的驱动程序
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // Java7 支持try-with-resource语法,只要在try语句里面创建的资源,会自动关闭。
        try (
           // 2. 建立数据库连接
           Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
           // 3. 创建statement
           Statement statement = conn.createStatement();
           // 4. 查询语句,并返回结果
           ResultSet rs = statement.executeQuery("select id, name, money, role from account");
        ) {
            // 5. 遍历查询结果
            while (rs.next()) {
                System.out.println(rs.getInt(1) + "\t" +
                        rs.getString(2) + "\t" +
                        rs.getDouble(3) + "\t" +
                        rs.getString(4));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  1. Preparation of non-transaction transfer function
    public void transfer(int fromId, int toId, double money) throws SQLException {
        Account fromAccount = accountDao.findById(fromId);
        Account toAccount = accountDao.findById(toId);
        fromAccount.setMoney(fromAccount.getMoney() - money);
        accountDao.update(fromAccount);
//        此处可以手动抛出一个异常,此时钱被转走,但接收者并不会收到。
//        if (true)
//            throw new RuntimeException();
        toAccount.setMoney(toAccount.getMoney() + money);
        accountDao.update(toAccount);
    }

When there is no transaction management, program function abnormalities may occur. For example, the last sentence of the above accountDao.update(toAccount);fails (ie the recipient does not receive the money), at a time accountDao.update(fromAccount);and perform successful. There will be reduction of money, but no arrival problems.

  1. Write transactional code that transfers
    public void transfer2(int fromId, int toId, double money) {
        Account fromAccount = accountDao.findById(fromId);
        Account toAccount = accountDao.findById(toId);

        try {
            System.out.println("begin");
            JdbcUtil.connection.setAutoCommit(false);
            fromAccount.setMoney(fromAccount.getMoney() - money);
            accountDao.update(fromAccount);
//            if (true)
//                throw new RuntimeException();
            toAccount.setMoney(toAccount.getMoney() + money);
            accountDao.update(toAccount);
            System.out.println("commit");
            JdbcUtil.connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                System.out.println("rollback");
                JdbcUtil.connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }

key point:

  • Open affairs
    JdbcUtil.conn.setAutoCommit(false);
  • Commit the transaction
    JdbcUtil.conn.commit();
  • When a transaction fails, the transaction is rolled back
    JdbcUtil.conn.rollback();

    JdbcUtil defined: https: //github.com/Jun67/spring-demo/blob/master/src/main/java/com/bailiban/day4/aop/aopxml/transaction/JdbcUtil.java

Write transactions using AOP

  1. Add four intercept method
  • Begin transaction
    // 开始事务,用于 before advice
    public void transaction_begin() throws SQLException {
        System.out.println("begin");
        connection.setAutoCommit(false);
    }
  • Commit the transaction
    // 提交事务,用于 after-returning advice
    public void transaction_commit() throws SQLException {
        System.out.println("commit");
        connection.commit();
    }
  • Roll back the transaction
    // 回滚事务,用于 after-throwing advice
    public void transaction_rollback() throws SQLException {
        System.out.println("rollback");
        connection.rollback();
    }
  • Recycling Resources
    // 回收资源,此处并没有关闭连接,对应于 after advice
    public void transaction_release() {
        System.out.println("release");
    }
  1. The interceptor configured to transfer method
<!--    事务处理相关方法-->
    <bean id="jdbcUtil" class="com.bailiban.day4.aop.aopxml.transaction.JdbcUtil" />

<!--    事务AOP配置-->
    <aop:config>
        <aop:aspect ref="jdbcUtil">
<!--            拦截transfer方法-->
            <aop:pointcut id="pc1" expression="execution(* com..transaction.*.transfer(..))"/>
<!--            transfer运行前,开启事务-->
            <aop:before method="transaction_begin" pointcut-ref="pc1" />
<!--            transfer运行结束后,提交事务-->
            <aop:after-returning method="transaction_commit" pointcut-ref="pc1" />
<!--            异常回滚-->
            <aop:after-throwing method="transaction_rollback" pointcut-ref="pc1" />
<!--            即使出现异常,after方法也会执行,模拟连接资源回收-->
            <aop:after method="transaction_release" pointcut-ref="pc1" />
        </aop:aspect>
    </aop:config>

Guess you like

Origin www.cnblogs.com/cheng18/p/12098417.html