内容简介:记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:
记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。
1、到底是什么是AOP?
所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下, 横切 扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。
2、AOP相关术语
在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:
-
连接点(Joinpoint) :在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后;
-
切点( Pointcut ) :所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;
-
增强( Advice ) :增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;
-
目标对象(Target) :增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;
-
引介( Introduction ) :一种特殊的增强,它可以为类添加一些属性喝方法;
-
织入( Weaving ) :织入就是讲增强逻辑添加到目标对象的过程;
-
代理( Proxy ) :一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;
-
切面( Aspect ) :切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;
3、AOP功能实践
我们这里主要是学习SpringBoot中的一些功能,所以我们这里用的是SpringBoot工程,版本也是最新的2.0.5版本。
创建SpringBoot工程就不说了,我们直接引入Maven的依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- 引入AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<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 :环绕增强;
测试:
异常测试:
4、定义自定义注解
应用场景 :在我之前上个项目的时候,有这样一个注解,就是在访问其他接口的时候必须要登录,那么这个时候我们就定义一个注解,让它去对用户是否登录进行校验,那么基于这样的一个场景,我们来定义一个校验登录的注解。
创建一个注解:
@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和自定义注解了吗?我把源码的地址放在下面,有兴趣的朋友可以看看。
GitHub地址 :https://github.com/liangbintao/SpringBootIntegration.git
原创不易,如果感觉不错,给个:+1:顺便扩散一下吧!
更多内容请关注“ 一个 程序员 的成长 ”
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 更加灵活的参数校验,Spring-boot自定义参数校验注解
- SpringBoot实现通用的接口参数校验,注解实战
- 来了,来了,Mars-Java 的属性校验注解,支持作用域设置了
- vue实战 - 车牌号校验和银行校验
- 一坨一坨的 if/else 参数校验,终于被 Spring Boot 参数校验组件整干净了
- SpringMVC——数据校验
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Transcending CSS
Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99
As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!