Spring学习笔记(三)——AOP

AOP的一些基本概念

  • 面向对象编程(OOP)的弊端?

——当需要为多个不具有继承关系的而对喜爱那个引入同一个公共行为时,例如日志、安全监测等,我们必须在每个对象里引入公共行为,这样程序中就产生了大量的重复代码。

  • 如何理解AOP?

——简单来说,AOP可以理解为对原方法在不改动原码的情况下的一种增强手段。

AOP(Aspect Oriented Programming)面向切面编程是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合符,但是存在一定的弊端(比方说引入日志、安全监测等公共行为会出现大量的重复代码)。

AOP利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为(比如说日志)封装到一个可重用模块,并将其命名为"Aspect",即切面,那么,我们可以统一指定切面的执行时机。

  • 什么是切面?

——所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

  • AOP的原理?

——AOP的底层原理是动态代理模式,与java自带的代理模式不同,java自带的动态代理模式只能代理接口,而Spring下的AOP可以代理普通类。

  • Spring AOP的代理类从何而来?

——Spring中的AOP是由IoC容器创建和管理的。Spring创建代理的规则为:默认使用Java动态代理来创建AOP代理,当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理(也可以强制指定)

  • 程序员需要做什么事情?
  1. 定义核心业务逻辑
  2. 定义切入点
  3. 定义通知
  • AOP术语
术语解释
Aspect(切面)通常是一个类,数量不限。用来定义Pointcut和Advice
Joint point(连接点)程序执行期间的一个点,例如执行方法或处理异常。在Spring AOP中,连接点始终表示方法执行。
Advice(通知/增强)特定连接点的某个方面采取的操作。这是在程序执行期间通过 Spring AOP 框架实际被调用的代码。
Pointcut(切点)表示一组 joint point,在这里Advice将被执行。
Introduction(引入)在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
Target(目标对象)织入 Advice 的目标对象
Weaving(织入)将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程,可以在编译时,类加载时和运行时完成
  • Advice的分类
类型解释
Before advice(前置通知)在方法执行之前执行
After returning advice(返回后通知)在方法正常执行并返回结果后执行
After throwing advice(抛出异常后通知)如果执行方法抛出了异常就会执行
After (finally) advice(后置通知)方法执行之后执行,不受方法执行结果影响
Around advice(环绕通知)最常用的,在方法执行前或者执行后执行
  • 如何定义一个切面(Aspect)?

——Spring支持两种自定义切面的方式:基于模式和使用@AspectJ注解

方法描述
XML Schema based方面是使用常规类以及基于配置的 XML 来实现的。
@AspectJ based@AspectJ 引用一种声明方面的风格作为带有 Java 5 注释的常规 Java 类注释。
  • 通知执行的顺序?

——分为正常情况和异常抛出情况。

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

  • 切入点类型?

——Spring AOP支持以下AspectJ切入点指示符(PCD)用于切入点表达式:

execution:用于匹配方法执行连接点。这是使用Spring AOP时使用的主要切入点指示符。

within:限制匹配某些类型中的连接点(使用Spring AOP时在匹配类型中声明的方法的执行)。

this:限制与连接点的匹配(使用Spring AOP时执行方法),其中bean引用(Spring AOP代理)是给定类型的实例。

target:限制与连接点的匹配(使用Spring AOP时执行方法),其中目标对象(被代理的应用程序对象)是给定类型的实例。

args:限制与连接点的匹配(使用Spring AOP时执行方法),其中参数是给定类型的实例。

@target:限制与连接点的匹配(使用Spring AOP时执行方法),其中执行对象的类具有给定类型的注释。

@args:限制与连接点的匹配(使用Spring AOP时执行方法),其中传递的实际参数的运行时类型具有给定类型的注释。

@within:限制匹配到具有给定注释的类型中的连接点(使用Spring AOP时在具有给定注释的类型中声明的方法的执行)。

@annotation:限制连接点的匹配,其中连接点的主题(在Spring AOP中执行的方法)具有给定的注释。

  • 切入点表达式?

——Spring AOP用户可能execution最常使用切入点指示符。执行表达式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
            throws-pattern?)
        
  • 常见的切入点表达式示例:
  1. 执行任何公共方法
    execution(public * *(..))
  2. 执行任何以set开头的方法
    execution(* set*(..))
  3. 执行AccountService接口定义的任何方法
    execution(* com.xyz.service.AccountService.*(..))
  4. 执行service包中定义的任何方法
    execution(* com.xyz.service.*.*(..))
  5. 执行service包下或者其子包下的任何方法
    execution(* com.xyz.service..*.*(..))
  6. 服务包中的任何连接点(仅在Spring AOP中执行方法)
    within(com.xyz.service.*)
  7. 代理实现AccountService接口的任何连接点(仅在Spring AOP中执行方法)
    this(com.xyz.service.AccountService)

使用@AspectJ注解的AOP实例

  • 准备工作:添加依赖
 <!--AOP的依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.7.RELEASE</version>
</dependency>
  • 步骤一:创建用于拦截的bean

在实际工作中,这个bean里面往往封装着满足业务需要的核心逻辑。但是,我想想在逻辑执行的前后加入日志来跟踪调试,直接修改原码显然是十分危险的,也不符合面向对象的设计方法,使用面向方面思路就是专门来解决这种问题的。

我们写一个简单的bean来模拟核心代码:

package com.xx.aop;

import org.springframework.stereotype.Component;

@Component
public class TestBean {
    private String testStr = "it is a test";

    public String getTestStr() {
        return testStr;
    }

    public void setTestStr(String testStr) {
        this.testStr = testStr;
    }

    public void doTest() {
        System.out.println(this + testStr);
    }
}

  • 步骤二:创建Advisor(增强器)

使用@AspectJ注解对POJO进行标注来创建一个Advisior。

我们要做的就是在所有类(包括TestBean )的doTest()方法执行前后来进行一些操作,这里用打印before或者after来代替。

package com.xx.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectTest {

    @Pointcut(value = "execution(* com.xx.aop.TestBean.doTest(..))")
    public void test() {
        // 声明一个名叫test的切入点
        // 该切入点与TestBean类下的doTest()方法匹配
    }

    @Before("test()")
    public void beforeTest() {
        System.out.println("beforeTest...");
    }

    @After("test()")
    public void afterTest() {
        System.out.println("afterTest...");
    }

    @Around("test()")
    public Object aroundTest(ProceedingJoinPoint p) {
        System.out.println("around-before...");
        Object o = null;
        try {
            // 执行方法
            o = p.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around-after...");
        return o;
    }

}

  • 步骤三:修改配置文件
    XML是Spring的基础,要在这里开启AOP功能和开启注解配置功能。
<?xml version="1.0" encoding="utf-8" ?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--启用注解-->
    <context:annotation-config/>
    <!--开启注解扫描-->
    <context:component-scan base-package="com.xx.aop"/>
    <!--自动创建代理-->
    <aop:aspectj-autoproxy/>

</beans>
  • 测试
    验证AOP的神奇效果:
package com.xx.aop;

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

public class AopTest {
    public static void main(String[] args) {
    
        ApplicationContext context = 
        		new ClassPathXmlApplicationContext("Beans.xml");
        		
        TestBean test = (TestBean) context.getBean("testBean");
        
        test.doTest();
    }
}

不出意外的情况下控制台会打印:

around-before...							# 环绕通知
beforeTest...								# 前置通知
com.xx.aop.TestBean@7c83dc97it is a test 	# 方法执行
around-after...								# 环绕通知
afterTest...								# 后置通知

这样我们利用Spring实现了对doTest()方法的增强,辅助功能可以独立于核心业务之外,方便程序的扩展和解耦。

基于XML配置的AOP

我们仿照上面的aspect,改为在xml文件中定义aspect:

<aop:config>
    <!--一、声明一个Aspect,这个类我们已经定义好了-->
    <aop:aspect id="xmlAspect" ref="aspectTestXml">
        <!--定义一个切点-->
        <aop:pointcut id="testPoint" expression="execution(* com.xx.aop.TestBean.doTest(..))"/>
        <!--定义advice-->
        <aop:before method="beforeTest" pointcut-ref="testPoint"/>
        <aop:after method="afterTest" pointcut-ref="testPoint"/>
        <aop:around method="aroundTest" pointcut-ref="testPoint"/>
    </aop:aspect>
</aop:config>

<bean id="aspectTestXml" class="com.xx.aop.AspectTestXml"></bean>
<bean id="testBean2" class="com.xx.aop.TestBean"></bean>

测试:

package com.xx.aop;

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

public class AopTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        TestBean test = (TestBean) context.getBean("testBean2");
        test.doTest();
    }
}

结果:

beforeTest...
around-before...
com.xx.aop.TestBean@6ad82709it is a test
around-after...
afterTest...
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值