IOC资源管理与PropertySource

91 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情

IOC资源管理

jdk原生的资源加载方式是用ClassLoader中的getResource方法和getResourceAsStream方法。Spring没有用jdk原生的资源管理方法,而是自己重新打造了一套。

原生jdk的url那一套资源加载方式,对于classpath或ServletContext中的资源来说没有标注的处理手段。别人的不足也是Spring大哥的优势。

java原生加载方式

java原生加载方式可以加载到下述资源:

  • 借助ClassLoader加载类路径下的资源(classpath)
  • 借助File加载文件系统的资源
  • 借助URL和不同的协议加载本地/网络上的资源

spring基于三种加载方式做了实现,并且新增了从ServletContext 域获取资源。

本文另一个较为重要的点是@PropertySource,看到这个注解很容易联想到properties资源的加载。

@PropertySource引入properties文件

我们拿jdbc的连接举例来说明: 新建一个jdbc的properties文件如下,并放到resource下:

jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driver-class-name=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456

接着编写配置类;

@Configuration
@ComponentScan("com.lyz.spring21")
@PropertySource("spring21/jdbc.properties")
public class JdbcPropertiesConfiguration {
}

编写资源配置模型类:

@Component
public class JdbcProperties {
    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driver-class-name}")
    private String driverClassName;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Override
    public String toString() {
        return "JdbcProperties{" +
                "url='" + url + ''' +
                ", driverClassName='" + driverClassName + ''' +
                ", username='" + username + ''' +
                ", password='" + password + ''' +
                '}';
    }
#get和set省略......

}

最后写我们的启动类:

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext(JdbcPropertiesConfiguration.class);
        System.out.println(ctx.getBean(JdbcProperties.class).toString());
    }
}

该示例运行结果如下;

image.png

这这基本操作大家应该耳熟能详了吧。
需要注意的一点是在配置类上我们是用来@PropertiesSource这个注解将我们的properties资源导入到spring,然后借助@Value注解为模型属性赋值。 其实PropertiesSource不仅能解析properties资源文件,也可以解析xml,只是我们编写这个xml需要严格根据格式来写才能解析,用的不多就不去深入讲解了。

PropertiseSource借助snake-yaml读取yml/yaml资源文件

上述properties写成yml文件的话就变成了下面这样(声明yml文件)

yml: 
  jdbc:
    url: jdbc:mysql://localhost:3306/test
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456

程序的改动在@Value处,每个jdbc.xxx要加个yml前缀。 最后的输出结果:

JdbcYmlProperty{url='${yml.jdbc.url}', driverClassName='${yml.jdbc.driver-class-name}', username='${yml.jdbc.username}', password='${yml.jdbc.password}'}

啊这,什么也没读出来,说明它是无法直接解析yml的。通常我们是借助snake-yaml来解析yml资源。 首先导入依赖;

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.26</version>
</dependency>

定义YmlSourceFactory类实现PropertySourceFactory接口。 第三步是把这个 YmlPropertySourceFactory 设置到 @PropertySource 中:

@PropertySource(value = "classpath:propertysource/jdbc.yml", factory = YmlPropertySourceFactory.class)

第四步借助snake-yaml将资源文件转换为Properties对象:

@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
    YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
    // 传入resource资源文件
    yamlPropertiesFactoryBean.setResources(resource.getResource());
    // 直接解析获得Properties对象
    Properties properties = yamlPropertiesFactoryBean.getObject();
    // 如果@PropertySource没有指定name,则使用资源文件的文件名
    return new PropertiesPropertySource((name != null ? name : resource.getResource().getFilename()), properties);
}

再进行测试解析出来了:

JdbcYmlProperty{url='jdbc:mysql://localhost:3306/test', driverClassName='com.mysql.jdbc.Driver', username='root', password='123456'}

上述就是本文讲的内容了,也是一些个人理解,有理解不正确的地方还请小伙伴们进行指正。