背景

在最近的工作室项目中用到了Jwt来替代Session实现授权与鉴权。为了实现代码和Jwt的参数的解耦,将Jwt的有关参数抽离到全局配置文件application.yml中。但是又怎么样把配置文件中的参数给读到Jwt的工具类中呢?

组成

  • JwtUtil.java - 将Jwt的功能实现封装成一个工具类
  • JwtProperties.java - 与配置文件的映射
  • application.yml - SpringBoot应用全局配置文件

实现

1. 映射

首先,声明一个Bean作与配置文件的映射。这个Bean我们就姑且称作Properties类,也就是上述所说的JwtProperties.java。其中,这个Bean需要拥有与配置文件“一样”的字段。为什么要加双引号?

其实读取配置文件有两种方式:一种是@ConfigurationProperties ,另外一种是@Value。他们的区别如下:

@ConfigurationProperties@Value
功能批量注入配置文件中的属性一个个指定
松散绑定(松散语法)支持不支持
SpEL不支持支持
JSR303数据校验支持不支持
复杂类型封装支持不支持

我们将使用@ConfigurationProperties这个注解来实现配置文件的映射。在这里我们就不详细说明两个注解区别,只需要知道@ConfigurationProperties是支持松散绑定的,即松散语法。

什么是松散语法?概念就不给出了,直接给出例子,一看就懂。

松散语法:privatekey = privateKey = private_key = private-key

而我们一般采用的是第四种方式,即通过-连接多个单词;而在Java变量的命名中,采用的是第二种,即驼峰法。

再者,需要注意的是:如果要使用@ConfigurationProperties注解,还需要使用@Component注解配套使用,把当前Propertities类交给IoC容器管理。

然后再生成getter和setter方法即可。

最终代码如下:

@Component
@ConfigurationProperties(prefix = "jwt")    //prefix是yml中的前缀
public class JwtProperties {
    private String privateSecret;
    private int expiresSecond;
    private int refreshSecond;

    // 省略getter和setter
}

2. 映射结果交给工具类

首先,想一个问题先,工具类怎么使用配置文件中的参数?既然Propeties类是配置文件的映射结果,那么Properties类就替代了配置文件的地位。在工具类中要读取到配置就要获取到Properties类的成员变量。

那么问题来了,该怎么注入这个Properties类?

很明显地,工具类的方法大部分都是static修饰的方法,也就是说不需要实例化工具类的对象,直接通过类名来调用方法。然而如果是静态方法的话,也就只能调用静态成员,这时候就需要声明一个静态的jwtProperties变量,然后紧接着使用@AutoWired自动注入,代码如下:

@AutoWired
private static JwtProperties jwtProperties;

这一切好像都很平静,没得任何问题。

但是结果是无法注入的,因为Spring的DI不支持DI目标是static的,只能是实例变量。而实例变量是可以给静态变量赋值的,这时候就需要再生成一个实例变量,提供JDK提供的@PostConstruct注解实现实例变量给静态变量赋值,代码如下:

@Autowired
private JwtProperties jwtProperties;        //依赖注入不支持给static的变量注入
private static JwtProperties staticJwtProperties;

@PostConstruct
public void init(){
    staticJwtProperties = this.jwtProperties;
}

在这里简单介绍一下@PostConstuct注解。

注解作用:在构造方法被调用后执行被注解的方法。在我们现在这个场景中,也就是说当前类被实例化后(通过IoC),借助实例变量给静态变量赋值。

Bean初始化执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

嗯,好的。这样好像解决了,能实现功能达到我的目的了,但是我看着很不爽!!!无端端又多了一个变量。

然后我就又开始查资料了,结果发现一个目前为止比较好的解决方案。

首先,把原来的成员变量转移到方法的形参中,通过形参给静态变量赋值。这时候@AutoWired的另外一个作用就上场了,@AutoWired不仅支持作用于变量中,还支持作用在方法上,此时的作用是给方法的形参进行DI。

最终代码如下:

private static JwtProperties JwtProperties;

/**
     * spring容器会在类加载后自动注入这个方法的参数,并执行一遍方法。
     * 这就像static{}块语句会初始化执行,但顺序不一样。static先执行
*/
@Autowired
public void init(JwtProperties jwtProperties){
    JwtUtil.JwtProperties = jwtProperties;
}

到此为止就大功告成了,很清爽有没有!

©著作权归作者所有

发表评论

正在加载 Emoji