Spring AOP深入解析与实战应用

AOP基础概念

AOP(面向切面编程)是一种编程范式,它通过分离关注点(Separation of Concerns, SoC)来提高代码的可维护性和模块化程度。AOP主要依赖于代理设计模式,包括静态代理和动态代理。动态代理分为两种:

  • JDK动态代理:当目标对象实现了接口时,Spring AOP使用JDK Proxy机制创建代理对象。
  • CGLIB动态代理:当目标对象未实现接口时,Spring AOP使用CGLIB生成目标对象的子类作为代理对象。
代理模式的应用场景

AOP在多种场景下都能发挥重要作用,例如:

  1. 日志采集
  2. 权限控制
  3. 事务管理
  4. 全局异常处理
  5. 远程过程调用(RPC)
  6. 数据源代理
动态代理示例

下面是一个使用CGLIB实现转账业务中事务管理的例子:

  1. AccountService —— 转账业务逻辑的实现。
  2. ProxyBeanFactory —— 代理工厂,负责创建事务管理的代理对象。

AccountService:

@Override
public void transfer(String sourceName, String targetName, int money) {
    Account sourceAccount = accountMapper.findByAname(sourceName);
    Account targetAccount = accountMapper.findByAname(targetName);
    sourceAccount.setAmoney(sourceAccount.getAmoney() - money);
    targetAccount.setAmoney(targetAccount.getAmoney() + money);
    accountMapper.updateById(sourceAccount);
    accountMapper.updateById(targetAccount);
}

ProxyBeanFactory:

public class ProxyBeanFactory {
    private IAccountService accountService;
    private TransactionUtil transactionUtil;

    public IAccountService createProxy() {
        return (IAccountService) Enhancer.create(
            accountService.getClass(),
            new MethodInterceptor() {
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    Object result = null;
                    try {
                        transactionUtil.beginTx();
                        result = method.invoke(accountService, args);
                        transactionUtil.commitTx();
                    } catch (Exception e) {
                        transactionUtil.rollbackTx();
                    } finally {
                        transactionUtil.closeTx();
                    }
                    return result;
                }
            }
        );
    }

    // Setters for DI
}

applicationContext.xml 配置文件:

<bean id="accountService" class="com.yk.service.AccountServiceImpl">
    <property name="accountMapper" ref="mapperImp"/>
</bean>

<bean id="proxyService" factory-bean="factory" factory-method="createProxy"/>

<bean id="factory" class="com.yk.factory.ProxyBeanFactory">
    <property name="transactionUtil" ref="transactionUtil"/>
    <property name="accountService" ref="accountService"/>
</bean>

<bean id="controller" class="com.yk.controller.AccountControllerImpl">
    <property name="accountService" ref="proxyService"/>
</bean>
AOP常用术语
  • 连接点:程序执行中的某个特定点,如方法调用。
  • 切点:匹配连接点的规则,即AOP要切入的位置。
  • 通知:AOP框架执行的代码,可以是在方法前、方法后等位置执行的代码块。
    • AOP将抽取出来的共性功能称为通知;
    • 通知类型:以通知在上下文中的具体位置作为划分
      前置通知(Before)
      返回通知(After-returning)
      异常通知(After-throwing)
      后置通知(After)
      环绕通知(Around)
切入点表达式

execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表])) 的语法详解如下:

  1. 修饰符 可以省略,代表任意。
  2. 返回类型 可以使用 "*" 代表任意。
  3. 包名 可以使用 "*"".." 代表任意数量的任意名称。
  4. 类名与方法名 可以使用 "*" 代表任意。
  5. 参数列表 可以使用 ".." 代表任意数量和类型的参数。
示例配置

XML配置:

<aop:config>
    <aop:aspect id="aopAspect" ref="logger">
        <aop:pointcut id="dian" expression="execution(* com.yk.service.*.*(..))"/>
        <aop:before method="beforeMethod" pointcut-ref="dian"/>
        <aop:after-returning method="afterReturningMethod" pointcut-ref="dian"/>
        <aop:after-throwing method="afterThrowingMethod" pointcut-ref="dian"/>
        <aop:after method="afterMethod" pointcut-ref="dian"/>
        <aop:around method="aroundMethod" pointcut-ref="dian"/>
    </aop:aspect>
</aop:config>

注解形式:

@Aspect
@Component
public class TransactionAspect {
    @Autowired
    private TransactionUtil transactionUtil;

    @Pointcut("execution(* com.yk.service.*.*(..))")
    public void dian() {}

    @Before("dian()")
    public void beforeService() {
        System.out.println("前置通知");
    }

    @AfterReturning("dian()")
    public void afterReturningMethod() {
        System.out.println("返回通知");
    }

    @AfterThrowing("dian()")
    public void afterThrowingMethod() {
        System.out.println("异常通知");
    }

    @After("dian()")
    public void afterMethod() {
        System.out.println("后置通知");
    }

    @Around("dian()")
    public Object aroundService(ProceedingJoinPoint point) {
        Object result = null;
        try {
            transactionUtil.beginTx();
            result = point.proceed();
            transactionUtil.commitTx();
        } catch (Throwable e) {
            transactionUtil.rollbackTx();
            e.printStackTrace();
            System.out.println("异常通知");
        } finally {
            transactionUtil.closeTx();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值