当前位置: 首页 > wzjs >正文

网页游戏网站网址网站网络推广推广

网页游戏网站网址,网站网络推广推广,清远网站推广优化公司,linux新建网站目录 核心概念 通知类型 前置通知 环绕通知 异常通知 后置通知 返回通知 通知参数 通知顺序 实现Ordered接口 使用Order注解 定义点切入 点切入代号 点切入表达式 组合点切入表达式 共享点切入表达式 同类共享 分离共享 完全共享 使用AOP功能 创建项目 创…

目录

核心概念

通知类型

前置通知

环绕通知

异常通知

后置通知

返回通知

通知参数

通知顺序

实现Ordered接口

使用@Order注解

定义点切入

点切入代号

点切入表达式

组合点切入表达式

共享点切入表达式

同类共享

分离共享

完全共享

使用AOP功能

创建项目

创建目标对象

controller.HelloController

controller.UserController

使用五种通知类型

创建切面类

启动当前项目

访问控制器接口

测试异常返回后通知

测试其他点切入代号

AopTarget

Pointcuts


AOP(Aspect-oriented Programming,面向切面编程)是Spring框架的核心特性之一。

AOP允许在方法[之前、之后、之前和之后、抛出异常时、方法返回后]插入一段代码。

AOP使用了软件设计模式中的代理模式,插入代码的工作由AOP生成的代理对象完成。

核心概念

AOP中的几个重要的概念:

  • 连接点(Join point):可以简单理解为被插入代码的方法(方法的执行时机)

  • 切面(Aspect):通常指切面类,定义连接点的类

  • 通知(Advise):在连接点中插入代码

  • 点切入(Pointcut):用于匹配连接点的断言,通常指点切入表达式,就是符合一定规则的字符串

  • 编织(Weaving):将切面和和其他应用程序类型或对象连接起来,这个是由AOP框架完成的,与我们程序员无关

  • 目标对象(Target object):又叫做通知对象,指的是被插入代码的类的实例

  • AOP代理对象(AOP proxy):AOP框架创建的代理对象,用于实现通知的执行

通知类型

Spring AOP中包含了以下5种通知类型,对应不同的方法执行时机。

下文中会出现一些概念:

通知方法:使用AOP的通知注解的方法(比如@Before)

目标方法:指的就是连接点对应的方法,定义目标方法的类叫做目标对象。

前置通知

使用@Before注解定义前置通知。

@Before(value = "点切入表达式")
public void before() {}

前置通知是在连接点之前运行的通知,但不能阻止执行流进入连接点除非抛出异常)。

不能阻止执行流进入连接点”指的是在通知方法上通过return关键字返回一个值,并不能阻止目标方法的执行。

环绕通知

使用@Around注解定义环绕通知。

@Around(value = "点切入表达式")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("执行around()前...");Object data = joinPoint.proceed(); // 执行点切入方法System.out.println("方法的返回值:" + data);System.out.println("执行around()后...");return data;
}

环绕通知是围绕连接点(在连接点之前和之后)运行的通知。

定义环绕通知的方法必须要定义一个ProceedingJoinPoint类型的参数,通过其proceeds()方法调用目标方法。

异常通知

通过@AfterThrowing注解定义抛出异常后通知。

定义抛出异常后通知时,可以通过@AfterThrowing注解的throwing属性绑定方法抛出的异常对象。

只需要参数名称和throwing属性的值保持一致即可完成绑定。

@AfterThrowing(pointcut = "点切入表达式", throwing = "e")
public void afterThrowing(Exception e) {// 访问方法抛出的异常对象eSystem.out.println(e.getMessage());System.out.println("执行afterThrowing()...");
}

抛出异常后通知是在方法抛出异常退出时运行的通知,这个通知类似catch关键字的作用,只要方法运行时抛出了异常,就会执行这个通知的代码。

后置通知

通过@After注解定义抛出异常后通知。

后置通知又叫最终通知,无论连接点以何种方式退出(正常或特殊返回),都要运行通知。

@After(value = "点切入表达式")
public void after() {System.out.println("执行after()...");
}

这个通知类似finally关键字的作用,即使方法运行时因为抛出异常而退出,也会执行这个通知的代码。

返回通知

使用@AfterReturning注解定义方法返回后通知。

定义方法返回后通知时,可以通过@AfterReturning的returning属性将方法的返回值绑定到通知参数上。

@AfterReturning(pointcut = "点切入表达式", returning = "returnValue")
public void afterReturning(Object returnValue) {// 访问方法的返回值returnValue
}

在方法正常返回后运行的通知,如果方法运行过程中抛出了异常,这个通知不会被执行。

通知参数

所有通知类型的方法上都可以使用JoinPoint接口作为第一个参数。

环绕通知@Around的方法参数ProceedingJoinPoint就是JoinPoint接口的一个派生类。

JoinPoint这个接口中定义了几个常用的方法:

package org.aspectj.lang;import org.aspectj.lang.reflect.SourceLocation;public interface JoinPoint {/*** 获取连接点方法的参数*/Object[] getArgs();/*** 返回AOP代理对象*/Object getThis();/*** 获取目标对象*/Object getTarget();/*** 获取连接点方法的签名* 通过方法签名Signature可以获取方法和它所在的类的信息*/Signature getSignature();
}

通过Signature对象,可以获取目标对象的类的信息(类对象)

package cn.edu.sgu.www.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** @author heyunlin* @version 1.0*/
@Aspect
@Component
public class CustomAspect {@Before(value = "execution(public * cn.edu.sgu.www.controller.*.*(..))")public void before(JoinPoint joinPoint) {System.out.println("方法的参数:" + Arrays.toString(joinPoint.getArgs()));Signature signature = joinPoint.getSignature();System.out.println(signature.getDeclaringType());System.out.println("执行before()...");}}

我们可以通过点切入代号args匹配参数名称,然后在通知方法的参数上声明参数的类型,这样我们就能获取到方法的参数。

@After("点切入表达式 && args(name,..)")
public void after(String name) {// ...
}

共享点切入的写法

@Pointcut("点切入表达式 && args(name,..)")
private void pointcut(String name) {}@After(value = "pointcut(name)", argNames = "name")
public void after(String name) {// ...
}

通知顺序

当一个项目中有多个切面类时,如果一个方法被多个切面切入,可以自定义多个切面类的切入顺序。

实现Ordered接口

让切面类实现org.springframework.core.Ordered接口,重写getOrder()方法,返回一个数字。

指定的数字越小,越先被执行。

package cn.edu.sgu.www.aop;import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;/*** @author heyunlin* @version 1.0*/
@Aspect
@Component
public class CustomAspect implements Ordered {@Overridepublic int getOrder() {return 0;}}

使用@Order注解

在切面类上使用@Order注解的value属性指定顺序;指定的数字越小,越先被执行。

package cn.edu.sgu.www.aop;import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** @author heyunlin* @version 1.0*/
@Order(value = 0)
@Aspect
@Component
public class CustomAspect {}

定义点切入

点切入代号

点切入代号(Pointcut Designators,PCD)是点切入表达式的一部分。

Spring AOP支持在点切入表达式中使用以下代号: 经测试@target和@within的作用是一样的。

点切入代号代号说明
execution用于匹配方法执行连接点。
within限制匹配有特定类型的连接点(可以指定多个类型)。
this限制匹配Spring AOP代理对象是指定类型的实例的连接点。
target限制匹配目标对象是指定类型的实例的连接点。
args限制匹配参数是指定类型的实例的连接点。
bean限制匹配指定名称的Spring Bean的连接点(可以使用通配符)
点切入代号代号说明
@args将匹配限制在实际传递参数的运行时类型具有给定类型注解的连接点。
@target限制匹配到执行对象(方法)的类具有给定类型注解的连接点。
@within将匹配限制在具有给定注解的类型中的连接点。
@annotation将匹配限制在连接点的主题(连接点方法)具有给定注解的连接点。

有些代号需要组合使用,否则项目会让启动失败:args、@args、@target

点切入表达式

定义点切入需要指定点切入表达式,点切入表达式是用来表示一个或多个方法的模式匹配符,类似正则表达式。

点切入代号([访问修饰符] 返回值类型 类的全限定名.方法名(参数列表))

点切入表达式中可以使用通配符:

通配符作用
*匹配任意一个包名、类名,访问修饰符不能用*
(*)匹配任意一个参数
(..)匹配任意多个参数

组合点切入表达式

在定义点切入表达式时,可以使用&&、||和!来连接多个点切入表达式。

共享点切入表达式

点切入表达式可以通过方法指定,供其他通知使用。

同类共享

可以通过@Pointcut注解实现点切入表达式的共享。

@Pointcut("execution(public * cn.edu.sgu.www.controller.*.*(..))")
public void pointcut() {}@Before("pointcut()")
public void before() {}

分离共享

点切入甚至可以放在一个单独的类中

public class Pointcuts {@Pointcut("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void pointcut() { }
}

然后在切面类中,指定点切入表达式时,在前面加上保存点切入的类的全限定名

@Before("Pointcuts.pointcut()")
public void before() {}

如果切面类和定义点切入的类在同一个包下,可以不指定类的包名(如上代码)。

完全共享

当使用PCD组合符时,可以将每个点切入表达式都分开定义(这是使用AOP的最佳实践)。

public class Pointcuts {@Pointcut("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void executionPointcut() { }@Pointcut("args(String, ..)")public void argsPointcut() { }/*** 完全分离点切入表达式*/@Pointcut(executionPointcut() && argsPointcut())public void pointcut() { }
}

使用AOP功能

创建项目

在Intellij IDEA中创建一个springboot项目springboot-aop

添加依赖

修改pom.xml文件,添加aspectj的依赖

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

或者添加Spring Boot整合AOP的依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

完整的pom.xml文件的内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath /></parent><groupId>cn.edu.sgu.www</groupId><artifactId>springboot-aop</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot-aop</name><description>Spring Boot整合AOP案例项目</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

创建目标对象

创建两个控制器类,用来测试AOP。

两个控制器类除了类名和路径不一样,其他都没什么区别。

controller.HelloController

package cn.edu.sgu.www.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author heyunlin* @version 1.0*/
@RestController
public class HelloController {@GetMapping("/hello")public String hello() {return "Hello World!";}@GetMapping("/greet")public String greet(@RequestParam String name) {return "Hello " + name + "!";}}

controller.UserController

package cn.edu.sgu.www.controller;import org.springframework.web.bind.annotation.*;/*** @author heyunlin* @version 1.0*/
@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/hello")public String hello() {return "Hello World!";}@RequestMapping(value = "/greet", method = RequestMethod.GET)public String greet(@RequestParam String name) {return "Hello " + name + "!";}}

使用五种通知类型

创建切面类

创建切面类aop.CustomAspect来测试上面介绍的5种通知类型。

通过点切入表达式execution(public * cn.edu.sgu.www.controller.*.*(..))匹配cn.edu.sgu.www.controller包下的所有类的所有方法。

package cn.edu.sgu.www.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** @author heyunlin* @version 1.0*/
@Aspect
@Component
public class CustomAspect {@Before("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void before() {System.out.println("执行before()...");}@Around("execution(public * cn.edu.sgu.www.controller.*.*(..))")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("执行around()前...");Object data = joinPoint.proceed(); // 执行目标对象的方法System.out.println("执行around()后...");return data;}@AfterThrowing(pointcut = "execution(public * cn.edu.sgu.www.controller.*.*(..))", throwing = "e")public void afterThrowing(Exception e) {// 访问方法抛出的异常对象eSystem.out.println("异常提示信息:" + e.getMessage());System.out.println("执行afterThrowing()...");}@AfterReturning(pointcut = "execution(public * cn.edu.sgu.www.controller.*.*(..))", returning = "returnValue")public void afterReturning(Object returnValue) {// 访问方法的返回值returnValueSystem.out.println("方法的返回值:" + returnValue);System.out.println("执行afterReturning()...");}@After("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void after() {System.out.println("执行after()...");}}

启动当前项目

启动项目,此时项目的结构如下

访问控制器接口

访问HelloController或UserController中的hello()方法。

localhost:8080/hello

然后在Intellij IDEA的控制台中,可以看到执行了所有(除了异常返回后)通知的代码。

测试异常返回后通知

修改HelloController的greet()方法,通过null对象调用方法主动产生一个空指针异常。

package cn.edu.sgu.www.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author heyunlin* @version 1.0*/
@RestController
public class HelloController {@GetMapping("/hello")public String hello() {return "Hello World!";}@GetMapping("/greet")public String greet(@RequestParam String name) throws InterruptedException {// 主动产生NPEObject obj = null;obj.wait();return "Hello " + name + "!";}}

重启项目,访问HelloController的greet()方法。

localhost:8080/greet?name=Tom

可以看到浏览器给我们显示了500状态码,因为这个接口的方法运行时抛出了NullPointException。

并且我们没有通过try...catch...语句块处理异常。

通过控制台可以看到,已经执行了异常抛出时的通知。

将切面类的点切入表达式共享

package cn.edu.sgu.www.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** @author heyunlin* @version 1.0*/
@Aspect
@Component
public class CustomAspect {@Pointcut("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void pointcut() { }@Before("pointcut()")public void before() {System.out.println("执行before()...");}@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("执行around()前...");Object data = joinPoint.proceed(); // 执行目标对象的方法System.out.println("执行around()后...");return data;}@AfterThrowing(pointcut = "pointcut()", throwing = "e")public void afterThrowing(Exception e) {// 访问方法抛出的异常对象eSystem.out.println("异常提示信息:" + e.getMessage());System.out.println("执行afterThrowing()...");}@AfterReturning(pointcut = "pointcut()", returning = "returnValue")public void afterReturning(Object returnValue) {// 访问方法的返回值returnValueSystem.out.println("方法的返回值:" + returnValue);System.out.println("执行afterReturning()...");}@After("pointcut()")public void after() {System.out.println("执行after()...");}}

测试其他点切入代号

AopTarget

创建自定义注解类annotation.AopTarget,用于测试@开头的PCD

因为要在类、方法、方法的参数上使用@AopTarget注解,所以就指定可以在这个三个地方使用。

package cn.edu.sgu.www.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author heyunlin* @version 1.0*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface AopTarget {}

Pointcuts

创建aop.Pointcuts类保存所有点切入,用于测试所有点切入代号。

package cn.edu.sgu.www.aop;import org.aspectj.lang.annotation.Pointcut;/*** @author heyunlin* @version 1.0*/
public class Pointcuts {@Pointcut("execution(public * cn.edu.sgu.www.controller.*.*(..))")public void pointcut() { }/*** 匹配bean名称为helloController的类下所有方法(HelloController)* bean代号中也可以可以使用通配符:* bean(*)匹配所有bean* bean(hello*)匹配所有bean名称以hello开头的所有bean* bean(*Controller)匹配bean名称以Controller结尾的所有bean*/@Pointcut("bean(helloController)")public void beanPointcut() { }/*** 匹配HelloController下的所有方法(AOP代理对象是HelloController类型)*/@Pointcut("this(cn.edu.sgu.www.controller.HelloController)")public void thisPointcut() { }/*** 匹配HelloController下的所有方法(目标对象是HelloController类型)*/@Pointcut("target(cn.edu.sgu.www.controller.HelloController)")public void targetPointcut() { }/*** 匹配通过组合符||连接的所有类下的所有方法*/@Pointcut("within(cn.edu.sgu.www.controller.HelloController || cn.edu.sgu.www.controller.UserController)")public void withinPointcut() { }/*** 匹配只有一个String类型参数的方法* args代号的断言中要使用类的全限定名,java.lang包下的类可以不指定包名*/@Pointcut("pointcut() && args(java.lang.String)")public void argsPointcut() { }/*** 匹配参数的类型上使用了@AopTarget注解的所有方法* 在HelloController/UserController类的greet方法的参数的类型上使用@AopTarget注解进行测试*/@Pointcut("pointcut() && @args(cn.edu.sgu.www.annotation.AopTarget)")public void args_Pointcut() { }/*** 匹配使用了@AopTarget注解的所有类的所有方法* 在HelloController/UserController类上使用@AopTarget注解进行测试*/@Pointcut("pointcut() && @within(cn.edu.sgu.www.annotation.AopTarget)")public void within_Pointcut() { }/*** 匹配使用了@AopTarget注解的所有类的所有方法(同@within)* 在HelloController/UserController类使用@AopTarget注解进行测试*/@Pointcut("pointcut() && @target(cn.edu.sgu.www.annotation.AopTarget)")public void target_Pointcut() { }/*** 匹配使用了@AopTarget注解的所有方法* 在HelloController/UserController类的方法上使用@AopTarget注解进行测试*/@Pointcut("pointcut() @annotation(cn.edu.sgu.www.annotation.AopTarget)")public void annotation_Pointcut() { }
}

具体测试的方法就是修改CustomAspect的pointcut方法上的点切入表达式为Pointcuts.方法名()

这样就可以轮流使用点切入类Pointcuts下的所有点切入表达式去匹配不同的连接点了~


文章代码已经上传到gitee,有需要的可以去下载~

Spring Boot整合AOP案例项目https://gitee.com/muyu-chengfeng/springboot-aop.git


创作不易,如果看完之后觉得文章对你有帮助,或者觉得博主写的很好,不要忘了点赞+收藏哦~


http://www.dtcms.com/wzjs/459064.html

相关文章:

  • 开个送快餐网站怎么做图片优化软件
  • 网站关键字代码seo优化效果
  • 个人网页制作简单方法seo软件视频教程
  • 网站的弹窗广告怎么做淘宝关键词排名查询网站
  • 免费做请帖的网站天津百度
  • 沧州市做网站pc网站建设和推广
  • 中上网站建设新闻头条新闻
  • 论文中网站数据如何做脚注如何软件网站优化公司
  • 温州给企业做网站外贸推广
  • 网站首页html代码百度推广收费标准
  • 网站域名选择的原则合肥做网站推广
  • 一级a做爰片免费网站神马电影seo的培训课程
  • 内蒙古网站备案怎么做百度seo优化招聘
  • 上海电商网站设计营销活动
  • 网站的设计制作流程2345浏览器网址导航
  • 安卓代理ip软件360优化大师官方下载手机
  • 海口哪里做网站公司营销管理制度范本
  • cfa一级看多久网站百度关键词seo排名优化
  • 网站电话转化率宁波网站建设推广平台
  • wordpress 视频上传福州seo扣费
  • 生产管理软件app搜索引擎优化策略应该包括
  • 湖北外贸网站建设价格设计一个简单的网页
  • 制作网站费用明细广告公司接单软件
  • 建设部网站首页近三天发生的大事
  • 建站快车加盟图片识别 在线识图
  • 随州做网站生意怎么样seo就业
  • 专业做相册书的网站it培训班大概需要多少钱
  • 免费网站建设靠谱吗电商网站开发
  • 河南住房城乡建设厅官方网站网址查询网站
  • 做便民网站都需要提供什么如何推广一款app