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

2021-10-26  本文已影响0人  yscyber

1、概述

2、JDK 动态代理

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 动态代理

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;
    }

}
上一篇 下一篇

猜你喜欢

热点阅读