SpringAOP

1 概述

  • 面向切面编程
  • AOP(Aspect Oriented Programming),即面向切面编程,利用一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。
  • 所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
  • Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能。

2 技术名词

  • 连接点(Joinpoint):
    • 连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
    • 核心业务类中的方法
  • 切入点(Pointcut):
    • 被Spring切入连接点。
    • 核心业务类中被添加辅助功能的方法
  • 通知、增强(Advice):
    • 可以为切入点添加额外功能,分为:
      • 前置通知、
      • 后置通知、
      • 异常通知、
      • 最终通知、
      • 环绕通知等。
  • 目标对象(Target):
    • 代理的目标对象
  • 引介(Introduction):一种特殊的增强,可在运行期为类动态添加Field和Method。
  • 织入(Weaving):
    • 把通知应用到具体的类,进而创建新的代理类的过程。
  • 代理(Proxy):
    • 被AOP织入通知后,产生的结果类。
  • 切面(Aspect):
    • 由切点和通知组成,将横切逻辑织入切面所指定的连接点中。

3 案例

AccountServiceImpl
package com.sw.service.impl;

import com.sw.entity.Account;
import com.sw.service.AccountService;

public class AccountServiceImpl implements AccountService {
    @Override
    public Integer addAccount(Account account) {
        System.out.println("AccountServiceImpl ===> addAccount");
        System.out.println(10/0);
        return null;
    }

    @Override
    public Integer removeAccount(Integer id) {
        return null;
    }

    @Override
    public Integer modifyAccount(Account account) {
        return null;
    }

    @Override
    public Account queryAccount(Account account) {
        return null;
    }
}
增强类
package com.sw.advice;

/**
 * 事务增强类
 */
public class TranscationAdvice {

    public void begin(){
        System.out.println("事务开启...");
    }

    public void commit(){
        System.out.println("事务提交...");
    }

    public void rollback(){
        System.out.println("事务回滚...");
    }

    public void release(){
        System.out.println("释放资源...");
    }

    public void around(){
        System.out.println("环绕通知...");
    }

}
配置
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--  包扫描路径  -->
    <context:component-scan base-package="com.sw"></context:component-scan>

    <!--  放入原材料  -->
    <bean id="accountService" class="com.sw.service.impl.AccountServiceImpl"></bean>
    <bean id="transcationAdvice" class="com.sw.advice.TranscationAdvice" ></bean>

    <!--
        aop配置
            把切点和增强织入
    -->
    <aop:config>
        <!--
            配置切点
                id  切点的标识
                expression  找到切点
        -->
        <aop:pointcut id="pt" expression="execution(public Integer com.sw.service.impl.AccountServiceImpl.addAccount(com.sw.entity.Account))"/>

        <!--    配置切面    -->
        <aop:aspect ref="transcationAdvice">
            <aop:before method="begin" pointcut-ref="pt"></aop:before>
            <aop:after-returning method="commit" pointcut-ref="pt"></aop:after-returning>
            <aop:after-throwing method="rollback" pointcut-ref="pt"></aop:after-throwing>
            <aop:after method="release" pointcut-ref="pt"></aop:after>
        </aop:aspect>
    </aop:config>

</beans>
测试
package com.sw.account;

import com.sw.service.AccountService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAccount {

    @Test
    public void getAccountService01(){
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService = ioc.getBean(AccountService.class);
        Integer ret = accountService.addAccount(null);
    }
}

4 切点通配符

<!--匹配参数-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.sw.aaron.aop.basic.User))" />
<!--匹配方法名(无参)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--匹配方法名(任意参数)-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--匹配返回值类型-->
<aop:pointcut id="myPointCut" expression="execution(com.sw.aaron.aop.basic.User *(..))" />
<!--匹配类名-->
<aop:pointcut id="myPointCut" expression="execution(* com.sw.aaron.aop.basic.UserServiceImpl.*(..))" />
<!--匹配包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.sw.aaron.aop.basic.*.*(..))" />
<!--匹配包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.sw.aaron.aop..*.*(..))" />

5 添加多个通知

创建Logger增强类
package com.sw.advice;

import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Date;

public class LoggerAdvice {
    Logger logger = LoggerFactory.getLogger(Logger.class);

    public void begin(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        logger.debug(target + "==>" + name + "==>方法即将执行,开启日志记录..." + new Date() + (args==null?null: Arrays.toString(args)));
    }
}
增加切面配置
<aop:aspect ref="loggerAdvice">
	<aop:before method="begin" pointcut-ref="pt"></aop:before>
</aop:aspect>

6 获取切点数据

  • 获取切点所在的对象
  • 获取切点的名称
  • 获取切点中的数据
package com.sw.advice;

import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Date;

public class LoggerAdvice {
    Logger logger = LoggerFactory.getLogger(Logger.class);

    public void begin(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        logger.debug(target + "==>" + name + "==>方法即将执行,开启日志记录..." + new Date() + (args==null?null: Arrays.toString(args)));
    }
}

7 环绕通知

  • 可以去替代
    • 前置通知+后置通知+最终通知+异常通知
环绕通知
    public void around(ProceedingJoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        try {
            System.out.println("事务开启...携带参数:" + (args==null?null: Arrays.toString(args)));

            for (int i = 0; i < 10; i++) {
                System.out.println(new Random().nextInt(100));
                if (i == 6){
                    System.out.println(10/0);
                }
            }

            System.out.println("事务提交...");
        } catch (Exception e) {
            System.err.println("事务回滚...");
        } finally {
            System.out.println(joinPoint.getSignature().getName() + "==>方法运行结束,释放资源");
        }
    }

8 注解实现AOP

配置类
package com.sw.comfig;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "com.sw")
@EnableAspectJAutoProxy
public class SpringConfig {
}
通知类
package com.sw.advice;

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

import java.util.Arrays;
import java.util.Random;

/**
 * 事务增强类
 */
@Component
@Aspect
public class TransactionAdvise {

    @Pointcut("execution(* com.sw.service.impl..*(..))")
    public void pt(){}

    //@Before(value = "pt()")
    public void begin(){
        System.out.println("事务开启...");
    }

    //@After(value = "pt()")
    public void commit(){
        System.out.println("事务提交...");
    }

    //@AfterThrowing(value = "pt()")
    public void rollback(){
        System.out.println("事务回滚...");
    }

    //@AfterReturning(value = "pt()")
    public void release(){
        System.out.println("释放资源...");
    }

    @Around(value = "pt()")
    public void around(ProceedingJoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        try {
            System.out.println("事务开启...携带参数:" + (args==null?null: Arrays.toString(args)));

            for (int i = 0; i < 10; i++) {
                System.out.println(new Random().nextInt(100));
                if (i == 6){
                    System.out.println(10/0);
                }
            }

            System.out.println("事务提交...");
        } catch (Exception e) {
            System.err.println("事务回滚...");
        } finally {
            System.out.println(joinPoint.getSignature().getName() + "==>方法运行结束,释放资源");
        }
    }

}
测试
    @Test
    public void getAccountService04(){
        AnnotationConfigApplicationContext ioc = 
        	new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService accountService = ioc.getBean(AccountService.class);
        Account account = accountService.queryAccount(10010);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你读书了吗?

生活不易,赏点饭吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值