SpringAOP,数据开发,事务管理

博客围绕Spring AOP展开,介绍了AOP概念、Spring的通知类型,如环绕、前置、后置、异常和引介通知及其应用场景。还阐述了ProxyFactoryBean为其他Bean创建代理实例的方式,并通过环绕通知案例演示创建AOP代理过程,最后提及AspectJ开发和基于注解的声明式AspectJ。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP的概念

AOP概念

Spring的通知类型

• org. aopall iance. intercept. Method I nterceptor (环绕通知) 在目标方法执行前后实施增强,可以应用于曰志、事务管理等功能。
• org.springframework.aop.MethodBeforeAdvice (前置通知) 在目标方法执行前实施增强,可以应用于权限管理等功能。
• org.springframework.aop.AfterReturningAdvice (后置通知) 在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。
• org.springframework.aop.ThrowsAdvice (异常通知) 在方法抛出异常后实施增强,可以应用于处理异常记录曰志等功能。
• org .springframework.aop.1 ntroduction I nterceptor (引介通知) 在目标类中添加一些新的方法和属性,可以应用于修改老版本程序(增强类)。

ProxyFactoryBean

ProxyFactoryBean 是 FactoryBean 接口的实现类, FactoryBean 负责实例化一个 Bean ,而 ProxyFactoryBean 负责为其他 Bean 创建代理实例。 在 Spring 中,使用 ProxyFactoryBean 是 创建 AOP 代理的基本方式。
传智教材中的ProxyFactoryBean的一些属性对 ProxyFactoryBean 类有了初步的了解后,接下来通过一个典型的环绕通知案例,来演示 Spring 使用 ProxyFactoryBean 创建 AOP 代理的过程
建一个ASpect类

public class CalcAspect {
    /**
     * 计算方法耗时
     * 环绕通知
     * @param joinPoint 代表连接点对象,该对象可以获取被代理方法的所有信息
     */
    public Object aroundM(ProceedingJoinPoint joinPoint) throws Throwable {

        // 获取连接点代表的方法的签名
        Signature signature = joinPoint.getSignature();
        log.debug("[aroundM] ---- 目标方法signature: " + signature);

        String methodName = signature.getName();
        Object[] args = joinPoint.getArgs();

        log.debug("[aroundM] ---- 目标方法"+methodName+"("+ Arrays.toString(args)+")开始执行");
        long start = System.currentTimeMillis();
        // 调用目标方法
        Object retVal = joinPoint.proceed();

        // 插入我们自己的逻辑代码
        long timer = System.currentTimeMillis() - start;

        log.debug("[aroundM] ---- 目标方法["+methodName+"("+ Arrays.toString(args)+")]执行结束,返回值: "+retVal+", 耗时: " + timer + "ms.");

        // 正常返回目标方法的返回值
        return retVal;
    }

    public void beforeM() {
        log.debug("[beforeM] ---- 目标方法开始执行");
    }

    public void afterReturningM(Object retVal) {
        log.debug("[afterReturningM] ---- 目标方法执行结束,返回值: " + retVal);
    }

    public void afterFinallyM() {
        log.error("[afterFinallyM] ---- 方法执行结束");
    }

    public void afterThrowing(Throwable throwable) {
        log.error("[afterThrowing] ---- 方法执行出错", throwable);
    }
}

创建接口Clac

public interface Calc {
    public int add(int num1, int num2);

    public int minus(int num1, int num2);

    public int multiply(int num1, int num2);
}

创建ClackImpl

public class CalcImpl implements Calc {
    @Override
    public int add(int num1, int num2) {
        long start = System.currentTimeMillis();
        int result = num1 + num2;
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long timer = System.currentTimeMillis() - start;

        System.out.println("方法执行结束, 耗时:" + timer + "ms.");
        return result;
    }
    public int minus(int num1, int num2) {
        // 模拟方法执行报错,便于看到after-throwing通知
        //        int ret = 9 / 0;
        return num1 - num2;
    }

    public int multiply(int num1, int num2) {
        log.info("执行multiply方法");
        return num1 * num2;
    }
}

MyClacProxy代理

public class MyCalcProxy extends CalcImpl{
    @Override
    public int multiply(int num1, int num2) {
        System.out.println("multiply 方法开始执行");
        int result = super.multiply(num1, num2);
        System.out.println("multiply 方法执行结束");
        return result;
    }
}

XML文件配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       ">

    <!-- calc 代表了原生的业务代码(将来被切入的对象) -->
    <bean id="calc" class="com.lanou3g.spring.simple.calc.CalcImpl"/>

    <!-- 切面类, 定义了我们要插入进去的代码。(将来会被织入到目标类中) -->
    <bean id="calcAspect" class="com.lanou3g.spring.simple.calc.CalcAspect"/>
  

    <aop:config>
        <!-- 这里仅演示可以在<aop:config>标签内配置多个切入点表达式和切面(同样的切面切入两次没有什么实际意义) -->
        <aop:pointcut id="all_calc_method" expression="execution(* com.lanou3g.spring.simple.calc.CalcImpl.*(..))"/>
        <!--<aop:pointcut id="all_calc_method2" expression="execution(* com.lanou3g.spring.simple.calc.CalcImpl.*(int, String))" />-->
        <aop:aspect ref="calcAspect">
            <aop:around method="aroundM" pointcut-ref="all_calc_method"/>
            <aop:before method="beforeM" pointcut-ref="all_calc_method"/>
            <aop:after-returning method="afterReturningM" pointcut-ref="all_calc_method" returning="retVal"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="all_calc_method" throwing="throwable"/>
            <aop:after method="afterFinallyM" pointcut-ref="all_calc_method"/>
        </aop:aspect>
        
    </aop:config>

</beans>

测试类

public class AppByTransactionXml {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("tx_conf.xml");
        testQuery(ctx);
        testTransaction(ctx);
    }

    static void testQuery(ApplicationContext ctx) {
        TeacherDaoImpl teacherDao = ctx.getBean(TeacherDaoImpl.class);
        List<Teacher> teacherList = teacherDao.queryAll();
        for(Teacher teacher : teacherList) {
            System.out.println("id: " + teacher.getId()+", tname: " + teacher.getTname());
        }
    }

    static void testTransaction(ApplicationContext ctx) {
        TeacherDaoImpl teacherDao = ctx.getBean(TeacherDaoImpl.class);
        int rowEffect = teacherDao.insertTeacher(new Teacher("女儿国王"));
        System.out.println("影响了" + rowEffect + "行.");
    }
}

AspectJ开发

基于AspectJ的开发在这里插入图片描述在这里插入图片描述

基于注解的声明式 AspectJ

在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值