使用spring boot的切面注解,来简化登录代码,以及java元注解基本知识

目录

 

 

目录

1. 自定义LoginInfo注解

1.0 元注解

1.1 @Inherited

1.2 @Retention

1.3 @Target

1.4 @Documented

2 代码解析

2.0 定义的Class InfoAscept以及使用的@Pointcut 以及@Aspect

2.1.1 @Pointcut @Before("infoCut()")

2.1.2 ServletRequestAttributes


 


1. 自定义LoginInfo注解

import java.lang.annotation.*;


@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LoginInfo {
}

1.0 元注解

 元注解(meta-annotation)

@Target,@Retention,@Documented,@Inherited

这四个标准的元注解,那么都是有相对应的使用功能的。

 

1.1 @Inherited

在这个注解中,

@Inherited:这是一个标注注解,@Inherited阐述了某个被标注的类型是被继承的。 
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 

(理解其实就是:

1.当有这个元注解修饰的注解,那么当它修饰 父类的时候,子类也会继承这个注解!!!

2.但是接口的继承关系中,子接口不会集成父接口的任何注解!!!不管注解有没有被@Inherited修饰

3.那么一个类实现一个接口呢?类实现接口时不会继承任何接口中定义的注解)(也就是只针对类与类之间的继承可以实现)

1.2 @Retention

官方代码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}


public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

Reteniton的作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中~

SOURCE 被编译器忽略(就是源文件保留)

CLASS 注解将会被保留在Class文件中,但在运行时并不会被VM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略。

RUNTIME 保留至运行时。所以我们可以通过反射去获取注解信息。

转自 :https://blog.csdn.net/asdgbc/article/details/70196749

另外:javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。

1.3 @Target

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

其实就是明确修饰的目标!

取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域 (仅可用于注解类的成员变量)
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法 (比如controller中的方法)
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

1.4 @Documented

描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

 

2 代码解析

2.0 定义的Class InfoAscept以及使用的@Pointcut 以及@Aspect

代码经过了处理,主要讲的一个思想hhh 大概只有我看得懂

@Aspect
@Component
@Slf4j
public class InfoAscept {

    @Pointcut(value = "@annotation(com.******.common.annotion.LoginInfo)")
    public void infoCut(){}

     @Before("infoCut()")
    public void before(){
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String authToken = request.getHeader("X-Auth-Token");
        if(StringUtils.isBlank(authToken)){
            throw new ResultException(***错误的常量***,"");
        }

        //向账户系统发送请求携带了token然后还有Threadlocal中的golobalrequestId
        //然后从账户系统中获得账户信息
        String res = HttpUtils.sendJsonPost("***脱敏***");
        AccountAuthTokenBaseData accountAuthTokenBaseData = JsonUtils.fromJson(res, AccountAuthTokenBaseData.class);
        if(SUCC != accountAuthTokenBaseData.getCode()){
            throw new ResultException(accountAuthTokenBaseData.getCode(), accountAuthTokenBaseData.getMsg(), "");
        }
        AccountAuthTokenData accountAuthTokenData = accountAuthTokenBaseData.getResult();
        ThreadLocal.setUserInfo(accountAuthTokenData);
    }
}

2.1.1 @Pointcut @Before("infoCut()")

@Pointcut :这个应该说是切点,举个例子:
一个类(Show)里面有一个表演(display)的方法,在表演之前,应该有致辞(say)的方法,在表演之后,应该有鼓掌(hand)的方法。

了高内聚低耦合,表演的方法应该单独封装在一个类里面,致辞和鼓掌的方法应该另外封装,但在调用时必须按照顺序来调用执行。这时候就需要设置切面和切点了!

切面应该设置在致辞(say)和鼓掌(hand)方法所在的类上面,同时,要在类里面配置切点

转自:https://blog.51cto.com/12181171/2103016

那么对于登录过程中 切点其实就是提取信息,那么写了一个空的切点方法,然后在切点之前获得了登录信息。

那么PointCut()里面应该有配置登录的方法的路径!!!

还可以有@AfterReturning方法,在标记方法执行完了之后执行的~

标记方法就是上述代码中的infoCut 也就是被@Pointcut注解注释的方法~

 

这些配置完成了之后,调用切入点方法的时候,就会先进行执行before 然后执行完了@AfterReturning。

还可以有@AfterThrowing 也就是当切点抛出异常之后执行的~

其他使用场景:调用不到一个类中的一个方法。然后也可以通过设置切点、切面来解决。

这是很浅层的理解,还需要更多的实践学习~

2.1.2 ServletRequestAttributes

在项目中用到的代码就是

ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();

也就是获取Request请求最终的目的!

然后这个request可以获取到一些header信息!

其实就是一种Spring MVC获取request 和response的方式!

感觉上因为这是写在了 controller之上的注解上,所以需要用

在Spring API中提供了工具类RequestContextHolder,能够在Controller中获取request对象和response对象,使用方法如下

HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletResponse resp = ((ServletWebRequest)RequestContextHolder.getRequestAttributes()).getResponse();

需要注意的是如果直接使用这个工具类,则会抛出一个空指针异常。原因是需要先在web.xml配置RequestContextListener监听器:


      
          org.springframework.web.context.request.RequestContextListener
      

参考:https://www.cnblogs.com/winner-0715/p/6270513.html

2.2 总结

这种来让API验证登录的方式比较简洁,只需要一个注解

然后ascept 其实是为了来实现这个注解的方法的

比如LogAscept  还有一些Ascept

 

 

 

你可能感兴趣的