Spring&MVC应用----第二章

Spring AOP 编程

什么是AOP

在这里插入图片描述
快速入门:
某手机商店需要购买手机和销售手机,现要求购买和销售手机时记录日志。
需求分析: 本系统有两个业务操作:购买手机和销售手机。我们可以定义一个手机业务接口、一个手机业务接口
实现和一个日志操作类。
任务参考结果
在这里插入图片描述
实现步骤:

  1. 创建 Web 工程: phone。
  2. 创建手机业务接口: PhoneBiz,并定义两个业务操作方法: buyPhone 和 salePhone。代码如下所示:
package com.test;
public interface PhoneBiz {
public void buyPhone(int num);//购买手机
public void salePhone(int num);//销售手机
}
  1. 创建手机业务接口实现类: PhoneBizImpl。代码如下所示:
package com.test;
public class PhoneBizImpl implements PhoneBiz {
public void buyPhone(int num) {
System.out.println("手机进货,进货数量为"+num+"部");
}
public void salePhone(int num) {
System.out.println("销售手机,销售数量为"+num+"部");
}
}
  1. 创建一个日志操作类: LogUtil。代码如下所示:
package com.test;
import java.text.SimpleDateFormat;27
import java.util.Date;
public class LogUtil {
public void log(String type,int num){
System.out.println("日志: "+currentTime()+type+"手机"+num+"部");
}
public String currentTime(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
return sdf.format(new Date());
}
}

5
) 创建一个测试类: Test。代码如下所示:

package com.test;
public class Test {
public static void main(String[] args) {
PhoneBiz phoneBiz = new PhoneBizImpl();
phoneBiz.buyPhone(10);
}
}
  1. 项目结构如下图所示:
    在这里插入图片描述
    输出结果:
    在这里插入图片描述
    此处缺少日志操作,因为日志操作的代码从业务操作方法中提取出去了,业务方法在执行时并不知道有记录日志的方法存在。
    可设计一个针对业务操作的代理对象来解决这个问题。实现步骤:
    1.在刚刚的项目中添加一个业务对象的代理类: PhoneBizImplProxy。代码如下所示
package com.test;
public class PhoneBizImplProxy implements PhoneBiz {
private PhoneBiz phoneBiz = new PhoneBizImpl();//业务操作对象
private LogUtil logUtil = new LogUtil();//日志操作对象
public void buyPhone(int num) {
phoneBiz.buyPhone(num);
logUtil.log("购买", num);
}
public void salePhone(int num) {
phoneBiz.salePhone(num);
logUtil.log("销售", num);
}
}

注意:代理类必须和业务操作类实现同一个接口。
并且代理类中需要持有业务操作对象和日志操作对象,这样表面看起来是代理对象在工作,实际上是由业务对象和日志对象在工作。
2.修改测试类,让代理对象执行任务。代码如下所示

package com.test;
public class Test {
public static void main(String[] args) {
PhoneBiz phoneBiz = new PhoneBizImplProxy();
phoneBiz.buyPhone(10);
}
}

3.再次检查项目结构,如下图所示:
在这里插入图片描述
4.输出结果
在这里插入图片描述
AOP 是 Aspect-Oriented Programming 的简称,意思是面向切面编程。 AOP 是对 OOP 的补充和完善。比如刚才的问题,程序中所有的业务方法都需要日志记录、参数验证、事务处理,这些公共的处理如果放在每个业务方法里,系统会变的臃肿,而且很难去维护。散布在系统各处的需要在实现业务系统时关注的事情就被成为“ 切面” ,也称为关注点, AOP 的思想就是把这些公共部分从业务方法中提取出来,集中处理。

AOP 中包含许多新的概念与术语,说明如下:

  1. 切面 (Aspect):切面是系统中抽象出来的的某一个功能模块。
  2. 连接点 (Joinpoint):程序执行过程中某个特定的点,如调用某方法或者处理异常时。在 SpringAOP 中,连接点总是代表某个方法的执行。
  3. 通知 (Advice):通知是切面的具体实现,是放置“ 切面代码” 的类。
  4. 切入点 (Pointcut):多个连接点组成一个切入点,可以使用切入点表达式来表示。
  5. 目标对象 (Target Object):包含一个连接点的对象,即被拦截的对象。
  6. AOP 代理 (AOP Proxy): AOP 框架产生的对象,是通知和目标对象的结合体。
  7. 织入 (Weaving):将切入点和通知结合的过程称为织入。

测验作业

使用 Spring AOP 技术重构手机业务案例。
实现步骤:

  1. 新建一个 Java Web 工程: phone。
  2. 添加 Spring 和 AOP 所需的 jar 包。
    在这里插入图片描述
    jar包我放在文章下方的链接里,自取。
  3. 引入 AOP 命名空间。打开 Spring 配置文件“applicationContext.xml” ,在其中添加如下代码:
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
</beans>

简单翻译:引入 AOP 命名空间是为了能够在配置文件中使用 AOP 相关的 xml 标签,
如果引入后不能使用 AOP 标签,则很有可能命名空间配置错误或是网络不通畅。

  1. 创建业务处理接口: PhoneBiz,及其实现类 PhoneBizImpl。这两个类的代码不变,但是需要将其配置成 SpringBean,以便容器管理。
package com.test;
public interface PhoneBiz {
public void buyPhone(int num);//购买手机
public void salePhone(int num);//销售手机
}
package com.test;
public class PhoneBizImpl implements PhoneBiz {
public void buyPhone(int num) {
System.out.println("手机进货,进货数量为"+num+"部");
}
public void salePhone(int num) {
System.out.println("销售手机,销售数量为"+num+"部");
}
}

Spring 配置文件增加如下代码:

<bean id="phoneBiz" class="com.ysd.test.PhoneBizImpl"></bean>
  1. 创建日志管理类: LogAspect。代码如下所示:
package com.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.aspectj.lang.JoinPoint;
public class LogAspect {
public void before(JoinPoint jp) {
Object[] args = jp.getArgs();// 目标方法所有参数
String methodName = jp.getSignature().getName();// 获得目标方法名称
if ("buyPhone".equals(methodName)) {
System.out.println(currentTime() + "即将执行进货操作,数量为" + args[0]);
}
if ("salePhone".equals(methodName)) {
System.out.println(currentTime() + "即将执行销售操作,数量为" + args[0]);
}
}
public String currentTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
return sdf.format(new Date());
}
}
  1. 将日志管理类配置成一个 Spring Bean,在 Spring 配置文件中添加如下代码:
<bean id="logAspectBean" class="com.ysd.test.LogAspect"></bean>
  1. 在 Spring 配置文件中将日志管理类配置成一个切面。在 Spring 配置文件中添加如下代码:
<aop:config>
<!-- 配置一个可以被多个切面共享的切入点 -->
<aop:pointcut expression="execution(void *Phone(int))" id="p1"/>
<!-- 配置一个切面 -->34
<aop:aspect id="logAspect" ref="logAspectBean"></aop:aspect>
</aop:config>
  1. 配置通知。将 LogAspect 类中的的 before 方法定义成一个前置通知,和切入点 p1 关联起来,这样 before 方法就能够在目标方法执行之前先执行日志记录了。在 spring 配置文件中添加如下代码:
<aop:config>
<!--配置一个可以被多个切面共享的切入点 -->
<aop:pointcut expression="execution(void *Phone(int))" id="p1"/>
<!--配置一个切面 -->
<aop:aspect id="logAspect" ref="logAspectBean">
<!--配置一个前置通知 -->
<aop:before method="before" pointcut-ref="p1"/>
</aop:aspect>
</aop:config>
  1. 检查完整的配置文件,代码如下所示:
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--配置目标对象 -->
<bean id="phoneBiz" class="com.ysd.test.PhoneBizImpl"></bean>
<!--配置切面所需的bean -->35
<bean id="logAspectBean" class="com.ysd.test.LogAspect"></bean>
<aop:config>
<!--配置一个可以被多个切面共享的切入点 -->
<aop:pointcut expression="execution(void *Phone(int))" id="p1"/>
<!--配置一个切面 -->
<aop:aspect id="logAspect" ref="logAspectBean">
<!--配置一个前置通知 -->
<aop:before method="before" pointcut-ref="p1"/>
</aop:aspect>
</aop:config>
</beans>
  1. 编写测试类: Test。代码如下所示:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context= new
ClassPathXmlApplicationContext("applicationContext.xml");
PhoneBiz phoneBiz = (PhoneBiz) context.getBean("phoneBiz");
phoneBiz.buyPhone(10);
}
}
  1. 检查项目结构,如下图所示:
    在这里插入图片描述
  2. 输出结果:
    在这里插入图片描述

这里是jar包
https://pan.baidu.com/s/1IyiPOG7I6xC4ZAFLZfp6nQ 提取码:s1mp

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值