Spring-AOP面向切面编程

Spring-AOP面向切面编程

 项目源代码地址:https://gitee.com/codefarmer-zb/projects
一、概念:
  在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
二、为什么要使用AOP?
  我的理解是:
  因为我们项目中会有很多功能独立的类,而这些类更多是作为工具使用,但是这些工具用途广泛,我们不能每次要调用这些工具类(因为独立工具类之间互相调用- 你调我 我调你- 耦合大大增加,以后要使用这些工具类就失去了可重用性,而且调用的链条过长,就会导致代码耦合性高,且难以后期修改维护),或者就去改变它或者新创一个类似的类,或者有些业务需要多个不同的工具类共同完成,我们也不能直接在业务类中直接引用工具类,会导致耦合增加,那么我们就需要根据不同的业务需求去增强它的功能,所以我们要在保持各个工具类、业务类低耦合(即没有互相引用)的情况下,使得功能类、业务类之间能够互相配合工作,就得使用AOP面向切面的思想,在配置文件(spring.xml)搭配它们从而实现完整功能。搭配各个工具类和业务类,就要在IOC容器中创建它们的bean对象来引用,再使用进行切面配置。
三、具体操作:
  1、在配置文件内创建各个工具类的bean对象存入IOC容器帮我们管理(用的时候提取配置文件中的IOC容器就行,IOC会根据bean对象帮我们创建该工具对象)
  2、创建完bean对象后,我们就可以用aop进行切面配置。
  1)首先引用要使用的工具类
  2)给要加强的业务包或业务类或业务类的具体方法 加上 工具类的加强方法,
    before/ 被加强类方法体执行前执行
    after/被加强类方法体执行最后执行
    after-returning/被加强类方法体return前执行
    after-throwing/被加强类方法体出错时执行
    method/工具类方法名
    pointcut/切点 即要加强的范围
四、AOP入门案例:
1、项目目录结构
 
0
2、账户业务接口AccountService.interface
复制代码
package com.zb;

public interface AccountService {
    //接口中 都是连接点方法
    void createAccount();
    void updateAccount(int i);
    int deleteAccount(int i);
}
复制代码
3、AccountServiceImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.zb;
 
public class AccountServiceImpl implements AccountService{
    @Override
    public void createAccount() {
//        int i=3/0;
        System.out.println("账号创建");
    }
 
    @Override
    public void updateAccount(int i) {
        System.out.println("账号更新");
    }
 
    @Override
    public int deleteAccount(int i) {
        System.out.println("账号删除");
        return 0;
    }
}
3、日志类
复制代码
package com.zb;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 模拟打印日志
 * 即为我们将要做的增强功能
 */
public class Logger {
//    public void printLog(){
//        System.out.println("打印日志。。。。。");
//    }
    public void printLogBefore(){
        System.out.println("前置通知。。。。");
    }
    public void printLogAfter(){
        System.out.println("后置通知。。。。");
    }
    public void printLogError(){
        System.out.println("错误通知。。。。");
    }
    public void printLogFinally(){
        System.out.println("最终通知。。。。");
    }
    public void printLogAround(ProceedingJoinPoint pjp){
        System.out.println("环绕通知。。。");
        //模拟其他4类通知
        printLogBefore();
        //执行业务方法
        try{
            //业务方法参数
            Object[] args=pjp.getArgs();
            Object result=pjp.proceed(args);
            //
            printLogAfter();
        } catch (Throwable throwable) {
            printLogError();
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }finally {
            printLogFinally();
        }
    }
}
复制代码
4、spring.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:aop="http://www.springframework.org/schema/aop"
       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">
<!--
    AOP相关配置
        1、配置将要增强的对象
        2、让IOC容器创建通知对象

     <aop:config>标签开始配置
        <aop:aspect>开始配置切面
            id:该切面的唯一标志符
            ref:配置通知对象的id
            <aop:before>前置通知
                method:通知对象的加强方法名
                pointcut:配置切入点 切入点语法:execution(表达式) 表达式:访问修饰符 返回类型 包名 类名 方法名(参数类型)
                execution(public void com.zb.AccountService.createAccount())
                类名可以使用* 表示全部包中所有类
                    public void com.zb.*.createAccount()
                方法名可以使用* 表示全部类中所有方法
                    public void com.zb.*.*()
                包名 * 表示当前包的所有包
                    public void *.zb.*.*()
                包可以使用 *..  来缩写来匹配所有的包名
                    public void *..*.*()
                全通配写法: * *..*.*(..)
                参数:
                    基本类型 int  void *..*.*(int)
                    引用类型 是用全类名 java

                实际应用:com.zb.service.*.*(..)
                    实际应用中 可能会在服务层中增强所有类的所有方法com.zb.service.*.*(..)
-->
    <bean id="accountService" class="com.zb.AccountServiceImpl" ></bean>
    <bean id="logger" class="com.zb.Logger" ></bean>
    <aop:config>
        <aop:aspect id="aspect1" ref="logger">
            <aop:around method="printLogAround" pointcut="execution(* com.zb.*.*())"/>
            <!--            前置通知 在方法调用前通知-->
<!--            <aop:before method="printLogBefore" pointcut="execution(* com.zb.*.*())"/>-->
<!--            &lt;!&ndash;            后置通知 在方法调用后通知&ndash;&gt;-->
<!--            <aop:after-returning method="printLogAfter" pointcut="execution(* com.zb.*.*())"/>-->
<!--            &lt;!&ndash;            错误通知 在方法调用出错通知&ndash;&gt;-->
<!--            <aop:after-throwing method="printLogError" pointcut="execution(* com.zb.*.*())"/>-->
<!--            &lt;!&ndash;            最终通知 在方法调用结束后通知&ndash;&gt;-->
<!--            <aop:after method="printLogFinally" pointcut="execution(* com.zb.*.*())"/>-->
        </aop:aspect>
    </aop:config>
</beans>
复制代码
5、测试类AccountServiceImplTest.java
复制代码
package com.zb;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class AccountServiceImplTest {
    @Autowired
    private AccountService accountService;
    @Test
    public void createAccount() {
        accountService.createAccount();
//        accountService.deleteAccount(0);
//        accountService.updateAccount(0);
    }
}
复制代码

 推荐参考文章:https://www.cnblogs.com/xrq730/p/7003082.html

参考文章:https://www.cnblogs.com/wang-meng/p/5641549.html

posted @ 2021-08-06 22:16  ITbing  阅读(51)  评论(0)    收藏  举报