美文网首页
113、【JavaEE】【Spring】Spring AOP(1

113、【JavaEE】【Spring】Spring AOP(1

作者: yscyber | 来源:发表于2021-10-26 01:45 被阅读0次

1、概述

  • AOP 面向切面编程,AOP 可以对代码进行“增强”并且以松耦合的形式进行“增强”。

  • 松耦合的增强例子:对于数据的“增删改”,引入事务的方式来确保数据的准确性。传统的编程中,事务机制代码(比如“开启事务”、“提交事务”、“回滚事务”等)是和业务逻辑代码(数据“增删改”)编写在一块。这种情况下,就是一种严重的耦合。而 AOP 可以将两部分代码分离,形成松耦合。提高可读性和可维护性。

  • Spring AOP 的机制基于的是动态代理。Java 中常见的动态代理技术有两种,一种是 JDK 动态代理,一种是 cglib 动态代理。

2、JDK 动态代理

  • 基于接口的动态代理技术。所代理的类必须是实现接口的类(至少实现一个接口)。

  • 利用拦截器和反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强。

Spring-25
  • 案例:模拟(使用输出语句)“事务处理数据修改(转账)”
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
public class Account {

    private String id;

    private Integer amount;

}
import com.yscyber.spring.five.pojo.Account;

public interface AccountRepo {

    Account getAccountById(String id);

    int updateAccount(String id, Account account);

}
import com.yscyber.spring.five.pojo.Account;
import com.yscyber.spring.five.repo.AccountRepo;

import org.springframework.stereotype.Repository;

/**
 * 模拟访问数据库
 */
@Repository
public class AccountRepoImpl implements AccountRepo {

    @Override
    public Account getAccountById(String id) {
        return new Account(id, 1000);
    }

    @Override
    public int updateAccount(String id, Account account) {
        System.out.println("更新后账户信息:" + account);
        return 1;
    }

}
public interface AccountService {

    int transfer(String outAccountId, String inAccountId, Integer amount);

}
import com.yscyber.spring.five.pojo.Account;
import com.yscyber.spring.five.repo.AccountRepo;
import com.yscyber.spring.five.service.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 模拟“转账”
 * 由于采用动态代理,有关事务的代码可以抽取出来,使业务代码更纯净
 */
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountRepo accountRepo;

    @Override
    public int transfer(String outAccountId, String inAccountId, Integer amount) {
        Account outAccount = accountRepo.getAccountById(outAccountId);
        Account inAccount = accountRepo.getAccountById(inAccountId);

        System.out.println("转出账户原始信息:" + outAccount);
        System.out.println("转入账户原始信息:" + inAccount);

        outAccount.setAmount(outAccount.getAmount() - amount);
        inAccount.setAmount(inAccount.getAmount() + amount);

        accountRepo.updateAccount(outAccountId, outAccount);
        accountRepo.updateAccount(inAccountId, inAccount);
        
        return 1;
    }

}
import com.yscyber.spring.five.service.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

@Component
public class AccountServiceProxy {

    @Autowired
    private AccountService accountService;


    /**
     * 生成代理对象
     */
    public AccountService createAccountServiceProxy() {

        AccountService accountServiceProxy = null;

        // Proxy.newProxyInstance() 返回代理对象
        // Proxy.newProxyInstance() 参数1:被代理对象的类加载器
        // 参数2:被代理对象所实现的接口
        // 参数3:InvocationHandler,负责编写增强代码
        accountServiceProxy = (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("开启事务...");
                    // 执行原方法,参数1是被代理对象
                    result = method.invoke(accountService, args);
                    System.out.println("提交事务...");
                } catch (Exception e) {
                    System.out.println("回滚事务...");
                } finally {
                    System.out.println("释放资源等操作...");
                }
                return result;
            }
        });

        return accountServiceProxy;
    }

}
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.yscyber.spring.five"/>

</beans>
import com.yscyber.spring.five.proxy.AccountServiceProxy;
import com.yscyber.spring.five.service.AccountService;

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(locations = {"classpath:applicationContext.xml"})
public class MySpringTest {

    @Autowired
    private AccountServiceProxy accountServiceProxy;

    @Test
    public void test1() {
        AccountService accountService = accountServiceProxy.createAccountServiceProxy();
        accountService.transfer("1", "2", 100);
    }

}

/*
开启事务...
转出账户原始信息:Account(id=1, amount=1000)
转入账户原始信息:Account(id=2, amount=1000)
更新后账户信息:Account(id=1, amount=900)
更新后账户信息:Account(id=2, amount=1100)
提交事务...
释放资源等操作...
*/

3、cglib 动态代理

  • 基于父类的动态代理技术。在某个类没有实现接口的情况下,可以采用 cglib 实现动态代理。

  • 动态生成一个要被代理的类的子类,动态生成的子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强。

Spring-26
  • 案例:模拟(使用输出语句)“事务处理数据修改(转账)”
package com.yscyber.spring.five.proxy;

import com.yscyber.spring.five.service.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class AccountServiceProxy {

    @Autowired
    private AccountService accountService;

    /**
     * 生成代理对象
     */
    public AccountService createAccountServiceProxy() {

        AccountService accountServiceProxy = null;

        accountServiceProxy = (AccountService) Enhancer.create(accountService.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result = null;
                try {
                    System.out.println("开启事务...");
                    // 执行原方法,参数1是被代理对象,参数2是方法入参
                    result = method.invoke(accountService, objects);
                    System.out.println("提交事务...");
                } catch (Exception e) {
                    System.out.println("回滚事务...");
                } finally {
                    System.out.println("释放资源等操作...");
                }
                return result;
            }
        });

        return accountServiceProxy;
    }

}

相关文章

网友评论

      本文标题:113、【JavaEE】【Spring】Spring AOP(1

      本文链接:https://www.haomeiwen.com/subject/xqcraltx.html