Spring的AOP思想的全面讲解(包含概念、注解和xml两种方式的实现)_chenjie的博客

一、Spring的AOP

AOP的思想:是Aspect oritention programming面想切面编程的简写。把一个个横切关注点(零散存在于业务方法中的功能代码)放进某一个模块中去,我们称这个模块为一个切面。每一个切面都能影响业务的某一个功能,切面的目的就是为了增强。

AOP的目的:AOP能将与业务无关、但是又为业务模块所共同调用的逻辑或其他内容进行封装;减少代码重复率,降低模块之间的耦合度,提高后期的可维护性。

AOP的优势:降低模块的耦合度、让系统更容易扩展、提高后期可维护度。换句话说就是,把多个方法前后相同的代码抽取出来,使用动态代理的方式来控制。运行的时候,先执行抽取出来的方法,再执行真实的方法。

AOP中的一些概念
Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。
Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强
Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。

使用AOP之前,下面三中方法中(权限控制、日志控制、事务控制),存在大量的代码冗余,不利于后期维护。
在这里插入图片描述
使用AOP之后,抽取共同的代码部分(权限控制、日志控制、事务控制),需要使用的时候再插入,可大大降低重复代码量,提高后期的可维护性。
在这里插入图片描述

二、PointCut语法

PointCut语法的作用,就是为了表达在哪些方法上,使用哪些方法对它进行增强。

AspectJ切入点语法如下
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

翻译成中文
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)

?:表示可以出现一次,或者不出现.没有问号,表示必须出现一次.
通配符:
*:匹配任何部分,只能表示一个单词
…: 可用于全限定名中和方法参数中,分别表示子包和0到N个参数

举例:
1、表示所有的public方法

	execution(public * *(..))

2、表示所有以set开头方法

	execution(* set*(..))

3、表示所有由method接口定义的任何方法

	execution(* com.xyz.service.method*(..))

4、表示所有在service包下的方法

	execution(* com.xyz.service.*.*(..))

5、表示所有在service包下,包括其子包中的方法

	execution(* com.xyz.service..*.*(..))

三、使用xml方式实现AOP

1、导入依赖包

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>

2、创建包、类,目录结构如下:
在这里插入图片描述
3、各个类中方法的撰写
Transaction类(需要被增强的类),里面包含两个方法,一个能正常执行的insert()方法,一个主动抛出异常的delete()方法。

public class Transaction {

    public void insert(){
        System.out.println("插入数据!!!");
    }

    public void delete(){
        System.out.println("删除数据!!!");
        System.out.println(1/0);
    }
}

TransactionManager类(使用里面的方法,去增强其他的类),里面包含四个方法,在不同时期对需要被增强的方法进行增强。

public class TransactionManager {
    
    public void before(){
        System.out.println("before前置增强!");
    }
    
    public void afterReturning(){
        System.out.println("afterReturning后置增强!");
    }
    
    public void throwing(){
        System.out.println("throwing异常增强!");
    }
    
    public void after(){
        System.out.println("after最终增强!");
    }
}

applicationContext.xml文件

	<!--把这两个类交给spring管理    -->
    <bean id="transaction" class="com.springaop.service.Transaction"></bean>
    <bean id="transactionManager" class="com.springaop.tx.TransactionManager"></bean>
    
    <!--AOP配置    -->
    <aop:config>
        <!--表示哪里的方法需要进行增强-->
        <aop:pointcut id="txPointCut" expression="execution(* com.springaop.service.*.*(..))"/>
        <!--增强的方法从哪个类中获取-->
        <aop:aspect ref="transactionManager">
            <!--四种增强方法-->
            <aop:before method="before" pointcut-ref="txPointCut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="txPointCut"/>
            <aop:after-throwing method="throwing" pointcut-ref="txPointCut"/>
            <aop:after method="after" pointcut-ref="txPointCut"/>
        </aop:aspect>
    </aop:config>

TransactionTest测试类

//使用spring的测试方式
@RunWith(SpringJUnit4ClassRunner.class)
//导入spring配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class TransactionTest {

    @Autowired
    private ApplicationContext context;

    @Test
    public void test1(){
        Transaction transaction = context.getBean(Transaction.class);
        transaction.insert();
    }

    @Test
    public void test2(){
        Transaction transaction = context.getBean(Transaction.class);
        transaction.delete();
    }
}

运行结果:
1、test1()方法的执行结果如下,可以看到该方法正常执行,增强方法也执行了。
在这里插入图片描述
2.test2()方法的执行结果如下,可以看到,我们主动编写的除零异常产生了,于是执行了异常增强方法。
在这里插入图片描述

四、使用注解方式实现AOP

1、导入依赖包
同上
2、创建类和包
同上
3、各个类中方法的撰写
Transaction类:同上

TransactionManager类(类上贴上Aspect注解,每个方法都贴上对应增强时期的注解)

@Aspect
public class TransactionManager {

    @Before("execution(* com.springaop.service.Transaction.*(..))")
    public void before(){
        System.out.println("before前置增强!");
    }

    @AfterReturning("execution(* com.springaop.service.Transaction.*(..))")
    public void afterReturning(){
        System.out.println("afterReturning后置增强!");
    }

    @AfterThrowing("execution(* com.springaop.service.Transaction.*(..))")
    public void throwing(){
        System.out.println("throwing异常增强!");
    }

    @After("execution(* com.springaop.service.Transaction.*(..))")
    public void after(){
        System.out.println("after最终增强!");
    }
}

applicationContext.xml文件,开启AOP注解扫描即可

	<!--把这两个类交给spring管理    -->
    <bean id="transaction" class="com.springaop.service.Transaction"></bean>
    <bean id="transactionManager" class="com.springaop.tx.TransactionManager"></bean>
    
    <!--AOP注解扫描    -->
    <aop:aspectj-autoproxy/>

TransactionTest测试类,同上

运行结果:
1、test1()方法的执行结果如下,正常执行。
在这里插入图片描述

2.test2()方法的执行结果如下,达到预期效果。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/cczxcce/article/details/107589078