专栏名称: Hollis
一个对Coding有着独特追求的人。
目录
相关文章推荐
51好读  ›  专栏  ›  Hollis

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

Hollis  · 公众号  ·  · 2018-10-21 08:30

正文

记得今年年初刚开始面试的时候,被问的最多的就是你知道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.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 :环绕增强;


测试:



异常测试:



4、定义自定义注解






请到「今天看啥」查看全文