转一个简单的例子,学习自定义注解和AOP

Posted 程序员顺仔和他的朋友们

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转一个简单的例子,学习自定义注解和AOP相关的知识,希望对你有一定的参考价值。

1、到底是什么是AOP?
【转】一个简单的例子,学习自定义注解和AOP

所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。

【转】一个简单的例子,学习自定义注解和AOP
2、AOP相关术语
【转】一个简单的例子,学习自定义注解和AOP

在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:

  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后

  • 切点(Pointcut):所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;

  • 增强(Advice):增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;

  • 目标对象(Target):增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;

  • 引介(Introduction):一种特殊的增强,它可以为类添加一些属性喝方法;

  • 织入(Weaving):织入就是讲增强逻辑添加到目标对象的过程;

  • 代理(Proxy):一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;

  • 切面(Aspect):切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;

【转】一个简单的例子,学习自定义注解和AOP
3、AOP功能实践
【转】一个简单的例子,学习自定义注解和AOP

我们这里主要是学习SpringBoot中的一些功能,所以我们这里用的是SpringBoot工程,版本也是最新的2.0.5版本。


创建SpringBoot工程就不说了,我们直接引入Maven的依赖:

<parent>
<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.5.RELEASEversion>
<relativePath/>
parent>

<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
properties>

<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jettyartifactId>
dependency>


<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.6.1version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.20version>
<configuration>
<skip>trueskip>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
executions>
plugin>
plugins>
build>


首先我们来创建一个Controller类:

@RestController
public class LoginController {

@GetMapping(value = "/username")
public String getLoginUserName(String userName, Integer age) {

return userName " --- " age;
}
}


创建切面:

@Aspect
@Component
public class LogAspect {

/**
* 功能描述: 拦截对这个包下所有方法的访问
*
* @param:[]
* @return:void
**/

@Pointcut("execution(* com.example.springbootaop.controller.*.*(..))")
public void loginLog() {
}

// 前置通知
@Before("loginLog()")
public void loginBefore(JoinPoint joinPoint) {

// 我们从请求的上下文中获取request,记录请求的内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

System.out.println("请求路径 : " request.getRequestURL());
System.out.println("请求方式 : " request.getMethod());
System.out.println("方法名 : " joinPoint.getSignature().getName());
System.out.println("类路径 : " joinPoint.getSignature().getDeclaringTypeName());
System.out.println("参数 : " Arrays.toString(joinPoint.getArgs()));
}

@AfterReturning(returning = "object", pointcut = "loginLog()")
public void doAfterReturning(Object object) {

System.out.println("方法的返回值 : " object);
}

// 方法发生异常时执行该方法
@AfterThrowing(throwing = "e",pointcut = "loginLog()")
public void throwsExecute(JoinPoint joinPoint, Exception e) {

System.err.println("方法执行异常 : " e.getMessage());
}

// 后置通知
@After("loginLog()")
public void afterInform() {

System.out.println("后置通知结束");
}

// 环绕通知
@Around("loginLog()")
public Object surroundInform(ProceedingJoinPoint proceedingJoinPoint) {

System.out.println("环绕通知开始...");

try {
Object o = proceedingJoinPoint.proceed();
System.out.println("方法环绕proceed,结果是 :" o);
return o;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}


注解概述:

  • @Apsect:将当前类标识为一个切面;

  • @Pointcut:定义切点,这里使用的是条件表达式;

  • @Before:前置增强,就是在目标方法执行之前执行;

  • @AfterReturning:后置增强,方法退出时执行;

  • @AfterThrowing:有异常时该方法执行;

  • @After:最终增强,无论什么情况都会执行;

  • @Afround:环绕增强;


测试:


【转】一个简单的例子,学习自定义注解和AOP


异常测试:


【转】一个简单的例子,学习自定义注解和AOP


【转】一个简单的例子,学习自定义注解和AOP
4、定义自定义注解
【转】一个简单的例子,学习自定义注解和AOP

应用场景:在我之前上个项目的时候,有这样一个注解,就是在访问其他接口的时候必须要登录,那么这个时候我们就定义一个注解,让它去对用户是否登录进行校验,那么基于这样的一个场景,我们来定义一个校验登录的注解。


创建一个注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {

String desc() default "验证是否登录";
}


创建一个AOP切面:

@Aspect
@Component
public class LoginAspect {

@Pointcut(value = "@annotation(com.example.springbootaop.annotation.Auth)")
public void access() {
}

@Before("access()")
public void before() {

System.out.println("开始验证用户是否登录...");
}

@Around("@annotation(auth)")
public Object around(ProceedingJoinPoint pj, Auth auth) {

// 获取注解中的值
System.out.println("注解中的值 : " auth.desc());
try {

// 检验是否登录 true 已经登录 false 未登录
Boolean flag = false;

if (flag == true) {
return "登录成功";
} else {
return "未登录";
}
} catch (Throwable throwable) {
return null;
}
}
}


测试未登录:



测试登录:



这样我们就可以简单的实现了一个登录校验的注解。


通过今天的分享你会使用AOP和自定义注解了吗?


本文来自公号一个程序员的成长。

以上是关于转一个简单的例子,学习自定义注解和AOP的主要内容,如果未能解决你的问题,请参考以下文章

(转)利用Spring AOP自定义注解解决日志和签名校验

HarmonyOS鸿蒙学习笔记@Component注解自定义组件简单说明

HarmonyOS鸿蒙学习笔记@Component注解自定义组件简单说明

HarmonyOS鸿蒙学习笔记@Component注解自定义组件简单说明

JPOM - AOP+自定义注解实现操作日志记录

JPOM - AOP+自定义注解实现操作日志记录