实验2 Spring AOP

一:实验目的

1、 理解Spring AOP原理和基本概念;

2、掌握基于XML/注解方式的AOP编程;

二:实验内容

1、定义交易接口:

public interface Transaction{

    public void income(float amount);//收入

    public void expenditure(float amount);//支出

}

定义银行账号实现Transaction接口:

public class BankAccount implements Transaction{

private String account;//账号

private float balance;//存款余额

public void income(float amount) //提示收入xxx,当前账户余额xxx

{          …            }

public void expenditure (float amount) //提示收入xxx,当前账户//余额xxx

{          …            }

… //其他方法略

推荐课程:【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=8613079943ff0493ec0d6d3985cc70cc

# 不会做的小伙伴记得多看几遍慢慢理解!

# 需要源码记得在评论下面留言哦!

2、基于XML实现AOP,使得账户余额变动前后进行信息提示;

在com.bankxml包下创建Transaction接口:

package com.bankxml;

public interface Transaction {

    public void income(float amount);//收入

    public void expenditure(float amount);//支出

    public void setBalance(float balance);//设置balance的初始值

    public void setAccount(String account);//设置account的初始值
}

在com.bankxml包下创建BankAccount实现类(实现Transaction接口):

package com.bankxml;

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

//@Component("BankAccount")
public class BankAccount implements Transaction {

//  有三种方法给属性赋初值,这里我采用基于setter的方式,其他两种在下面被注释了,
//  你们只需选中文本然后用快捷键ctrl+/就可以打开注解了,
//  不懂的小伙伴可以百度一下哦,多用快捷键可以提高编程效率
//    @Value("dgut")
    private String account;//账号
//    @Value("123")
    private float balance;//存款余额

    //构造方法
//    public BankAccount(String account, float balance) {
//        this.account = account;
//        this.balance = balance;
//    }

    //setter方法
    public void setAccount(String account) {
        this.account = account;
    }

    public void setBalance(float balance) {
        this.balance = balance;
    }

    @Override
    public void income(float amount) { //提示收入XXX,当前账户余额XXX

        System.out.println(balance + "元");
        balance += amount; //收入amount元
        System.out.println("当前账户:" + account + ";收入:" + amount +"元");
        System.out.print(balance + "元为");

    }

    @Override
    public void expenditure(float amount) {  提示支出XXX,当前账户余额XXX

        System.out.println(balance+"元");
        if(amount > balance) {
            System.out.println(balance);
            System.out.println("余额不够");
        }else {
            balance -= amount;
            System.out.println("当前账户:" + account + ";支出:" + amount + "元");
            System.out.print(balance + "元为");
        }

    }

}

在com.bankxml包下创建XmlAdvice类:

package com.bankxml;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Pointcut;

public class XmlAdvice {

    //基于XML方式
    //此方法无返回值所以用void即可,若有返回值用Object
    public void around (ProceedingJoinPoint pjp) throws Throwable { //提示收入XXX,当前账户余额XXX

        System.out.print("账户余额未变动前为:");
        pjp.proceed();
        System.out.println("当前账户余额!!!");

    }

}

在com.bankxml包下创建XmlAdviceTest测试类:

package com.bankxml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Scanner;

public class XmlAdviceTest {

    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Transaction transaction = (Transaction) ac.getBean("transaction");

        Scanner sc = new Scanner(System.in);

        System.out.println("请输入账户:");
        String account = sc.next();
        transaction.setAccount(account);

        System.out.println("请输入初始金额:");
        float balance = sc.nextFloat();
        transaction.setBalance(balance);

        while (true) {
            System.out.println("请选择操作选项:1.存款,2.取款,3,退出");
            String str = sc.next();
            if (str.equals("3")) {
                System.out.println("退出成功!");
                break;
            }
            switch (str) {
                case "1":
                    System.out.println("请输入存款金额:");
                    transaction.income(sc.nextFloat());
                    continue;
                case "2":
                    System.out.println("请输入取款金额:");
                    transaction.expenditure(sc.nextFloat());
                    continue;
                default:
                    System.out.println("输入错误,请重新输入!");
            }
        }


    }
}

运行结果:

基于XML方式的xml文件配置:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--三种方法在xml文件中给属性赋初值(只是想复习一下实验一),但我不在xml文件中给属性赋初值,我直接让用户自己输入-->
    <!--1、基于注解的装配方式,即给属性赋初值-->
<!--    <context:component-scan base-package="bankxml.BankAccount"></context:component-scan>-->

    <!--基于XML方式配置-->
    <!--BankAccount对象-->
    <bean id="transaction" class="com.bankxml.BankAccount">
        <!--2、基于setter方法注入,即给属性赋初值-->
<!--        <property name="account" value="dgut"></property>&lt;!&ndash;账号&ndash;&gt;-->
<!--        <property name="balance" value="123"></property>&lt;!&ndash;存款余额&ndash;&gt;-->
        <!--3、基于构造方法注入,即给属性赋初值-->
<!--        <constructor-arg name="account" value="dgut"></constructor-arg>&lt;!&ndash;账号&ndash;&gt;-->
<!--        <constructor-arg name="balance" value="123"></constructor-arg>&lt;!&ndash;存款余额&ndash;&gt;-->
    </bean>

    <!--增强所在的类的对象,切面类对象-->
    <bean id="xmlAdvice" class="com.bankxml.XmlAdvice"></bean>

    <!--aop配置核心一句话:在 切面 中配置 切入点 和 增强的(通知) 关系-->
    <!-- aop配置根标签,声明开始aop配置-->
    <aop:config>
        <!--全局的切入点-->
        <!--这样子写感觉代码有点冗余(为了不影响用户输入账号和初始金额),但是目前想不到更好的方法,希望小伙伴们可以提点意见-->
        <aop:pointcut id="pointcut1" expression="execution(* com.bankxml.Transaction.income(..))"></aop:pointcut>
        <aop:pointcut id="pointcut2" expression="execution(* com.bankxml.Transaction.expenditure(..))"></aop:pointcut>

<!--        这种写法有bug(即用户输出账户和初始金额界面受影响)-->
<!--        <aop:pointcut id="pointcut" expression="execution(* bankxml.BankAccount.*(..))"></aop:pointcut>-->
        <!--配置切面-->
        <aop:aspect ref="xmlAdvice">
            <!--配置切入点与通知的关系-->
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="pointcut1"></aop:around>
            <aop:around method="around" pointcut-ref="pointcut2"></aop:around>
        </aop:aspect>
    </aop:config>

</beans>

3、基于注解方式实现AOP,使得账户余额变动前后进行信息提示。

创建TransactionAnno接口:

package com.bankanno;

public interface TransactionAnno {

    public void income(float amount);//收入

    public void expenditure(float amount);//支出

    public void setBalance(float balance);//设置balance的初始值

    public void setAccount(String account);//设置account的初始值

}

创建BankAccountAnno实现类(实现TransactionAnno接口):

package com.bankanno;

import com.bankxml.Transaction;

public class BankAccountAnno implements TransactionAnno {

        private String account;//账号
        private float balance;//存款余额a

        //setter方法
        public void setAccount(String account) {
            this.account = account;
        }

        public void setBalance(float balance) {
            this.balance = balance;
        }

        @Override
        public void income(float amount) { //提示收入XXX,当前账户余额XXX

            System.out.println(balance + "元");
            balance += amount; //收入amount元
            System.out.println("当前账户:" + account + ";收入:" + amount +"元");
            System.out.print(balance + "元为");

        }

        @Override
        public void expenditure(float amount) {  提示支出XXX,当前账户余额XXX

            System.out.println(balance+"元");
            if(amount > balance) {
                System.out.println(balance);
                System.out.println("余额不够");
            }else {
                balance -= amount;
                System.out.println("当前账户:" + account + ";支出:" + amount + "元");
                System.out.print(balance + "元为");
            }

        }

}

创建AnnoAdvice类:

package com.bankanno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AnnoAdvice {

    //基于注解方式
    //切入点的配置,这样子写感觉代码有点冗余(为了不影响用户输入账号和初始金额),
    // 但是目前想不到更好的方法,希望小伙伴们可以提点意见
    @Pointcut("execution(* com.bankanno.BankAccountAnno.income(..))")
    public void pt1(){
    }
    @Pointcut("execution(* com.bankanno.BankAccountAnno.expenditure(..))")
    public void pt2(){
    }

    @Around("pt1()")
    public void around1(ProceedingJoinPoint pjp1) throws Throwable {
        System.out.print("账户余额未变动前为:");
        pjp1.proceed();
        System.out.println("当前账户余额!!!");
    }

    @Around("pt2()")
    public void around2(ProceedingJoinPoint pjp2) throws Throwable {
        System.out.print("账户余额未变动前为:");
        pjp2.proceed();
        System.out.println("当前账户余额!!!");
    }

}

创建AnnoAdviceTest测试类:

package com.bankanno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Scanner;

public class AnnoAdviceTest {

    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        TransactionAnno transactionAnno = (TransactionAnno) ac.getBean("transactionAnno");

        Scanner sc = new Scanner(System.in);

        System.out.println("请输入账户:");
        String account = sc.next();
        transactionAnno.setAccount(account);

        System.out.println("请输入初始金额:");
        float balance = sc.nextFloat();
        transactionAnno.setBalance(balance);

        while (true) {
            System.out.println("请选择操作选项:1.存款,2.取款,3,退出");
            String str = sc.next();
            if (str.equals("3")) {
                System.out.println("退出成功!");
                break;
            }
            switch (str) {
                case "1":
                    System.out.println("请输入存款金额:");
                    transactionAnno.income(sc.nextFloat());
                    continue;
                case "2":
                    System.out.println("请输入取款金额:");
                    transactionAnno.expenditure(sc.nextFloat());
                    continue;
                default:
                    System.out.println("输入错误,请重新输入!");
            }
        }

    }

}

运行结果:

基于注解方式的xml文件配置:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--基于注解方式-->
    <bean id="transactionAnno" class="com.bankanno.BankAccountAnno"></bean>
    <bean id="annoadvice" class="com.bankanno.AnnoAdvice"></bean>
    <!--开启注解aop-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

JavaEE实验三中的Spring AOP是指Spring框架中的面向切面编程。它可以在不修改原有代码的情况下,通过在程序运行时动态地将代码织入到类的指定方法中,实现对方法的增强。具体来说,Spring AOP主要包括两种代理方式:JDK动态代理和CGLIB动态代理。其中,JDK动态代理只能代理实现了接口的类,而CGLIB动态代理则可以代理任意类。在Spring AOP中,我们可以通过XML配置或注解来定义切面和通知,实现对目标方法的增强。 以下是JavaEE实验三中Spring AOP的基本步骤: 1. 定义切面类,即包含通知的类。 2. 定义通知,即增强的代码逻辑。 3. 配置切面和通知,可以通过XML配置或注解来实现。 4. 在需要增强的方法上添加切点,即指定需要增强的方法。 5. 运行程序,观察增强效果。 下面是一个使用XML配置的Spring AOP的例子: 1. 定义切面类和通知: ```java public class LogAspect { public void before() { System.out.println("方法执行前"); } public void after() { System.out.println("方法执行后"); } } ``` 2. 在XML配置文件中定义切面和通知: ```xml <bean id="logAspect" class="com.example.LogAspect"/> <aop:config> <aop:aspect ref="logAspect"> <aop:before method="before" pointcut="execution(* com.example.Service.*(..))"/> <aop:after method="after" pointcut="execution(* com.example.Service.*(..))"/> </aop:aspect> </aop:config> ``` 3. 在需要增强的方法上添加切点: ```java @Service public class UserServiceImpl implements UserService { @Override public void addUser(User user) { System.out.println("添加用户:" + user.getName()); } } ``` 4. 运行程序,观察增强效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值