目录
目录
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
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LoginInfo {
}
元注解(meta-annotation)
@Target,@Retention,@Documented,@Inherited
这四个标准的元注解,那么都是有相对应的使用功能的。
在这个注解中,
@Inherited:这是一个标注注解,@Inherited阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
(理解其实就是:
1.当有这个元注解修饰的注解,那么当它修饰 父类的时候,子类也会继承这个注解!!!
2.但是接口的继承关系中,子接口不会集成父接口的任何注解!!!不管注解有没有被@Inherited修饰
3.那么一个类实现一个接口呢?类实现接口时不会继承任何接口中定义的注解)(也就是只针对类与类之间的继承可以实现)
官方代码:
@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区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。
@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声明
描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
代码经过了处理,主要讲的一个思想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);
}
}
@Pointcut :这个应该说是切点,举个例子:
一个类(Show)里面有一个表演(display)的方法,在表演之前,应该有致辞(say)的方法,在表演之后,应该有鼓掌(hand)的方法。
了高内聚低耦合,表演的方法应该单独封装在一个类里面,致辞和鼓掌的方法应该另外封装,但在调用时必须按照顺序来调用执行。这时候就需要设置切面和切点了!
切面应该设置在致辞(say)和鼓掌(hand)方法所在的类上面,同时,要在类里面配置切点
转自:https://blog.51cto.com/12181171/2103016
那么对于登录过程中 切点其实就是提取信息,那么写了一个空的切点方法,然后在切点之前获得了登录信息。
那么PointCut()里面应该有配置登录的方法的路径!!!
还可以有@AfterReturning方法,在标记方法执行完了之后执行的~
标记方法就是上述代码中的infoCut 也就是被@Pointcut注解注释的方法~
这些配置完成了之后,调用切入点方法的时候,就会先进行执行before 然后执行完了@AfterReturning。
还可以有@AfterThrowing 也就是当切点抛出异常之后执行的~
其他使用场景:调用不到一个类中的一个方法。然后也可以通过设置切点、切面来解决。
这是很浅层的理解,还需要更多的实践学习~
在项目中用到的代码就是
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
这种来让API验证登录的方式比较简洁,只需要一个注解
然后ascept 其实是为了来实现这个注解的方法的
比如LogAscept 还有一些Ascept