真实工作中经常用到的Aware使用简介


1 前言

上篇文章《ApplicationContextAwareProcessor源码解析 + Aware接口简介》简单地介绍了Aware接口,本篇文章将介绍一下Aware的使用方法,由于spring中的Aware众多,这里仅仅抛砖引玉,本篇文章会介绍如下几个Aware:

  • BeanNameAware — 获取当前bean在IOC容器中的名字
  • EmbeddedValueResolverAware — el表达式解析原理
  • ApplicationContextAware — 工作中用到
  • MessageSourceAware — 工作中用到

下面对其进行一一介绍。


2 BeanNameAware和EmbeddedValueResolverAware使用简介

源码地址:https://github.com/nieandsun/spring-study

2.1代码开发

  • 实现BeanNameAware和EmbeddedValueResolverAware
package com.nrsc.springstudy.c072_bean_life_cycle.beans;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

/***
 * Description:
 *    实现了BeanNameAware,可以获取到当前bean在IOC容器中的名字
 *    注意该Aware的调用在前置处理器applyBeanPostProcessorsBeforeInitialization方法之前
 *
 *    实现了EmbeddedValueResolverAware,可以利用resolver来解析字符串表达式(el表达式)
 */
@Component
public class Tiger implements BeanNameAware, EmbeddedValueResolverAware {
    private String name = "老虎";

    public void setBeanName(String name) {
        System.err.println("当前bean的名字为:" + name);
    }

    public void setEmbeddedValueResolver(StringValueResolver resolver) {

        String val = resolver.resolveStringValue("当前系统为${os.name},表达式3*8的结果为:#{3*8}");
        System.err.println("解析后的字符串为===" + val);
    }
}

2.2 测试

测试效果如下:
在这里插入图片描述


3 ApplicationContextAware在工作中的使用

源码地址:https://github.com/nieandsun/NRSC-STUDY

3.1 应用场景介绍

实际项目中应该会遇到这种情况,我们引入了某个jar,该jar里有些bean会随着项目的启动注入到IOC容器里。


如果我们想使用这些bean时,或许很多时候都可以通过@Autowired的方式将其注入到我们自己的bean对象里去使用他们。


但是某些时候,我们却不能这样做,比如说某个工具类要使用这样的bean,如果使用了@Autowired的方式将依赖的bean注入到该工具类,那该工具类就得暴漏成一个bean注入到IOC容器,那别人使用这个工具类时就得通过@Autowired的方式将该工具类注入到要使用该工具类的bean对象里,这其实是很难让人接受的。


而且在多态的情况下,我们往往不知道真正要调用的是哪个具体的类,这时候想用@Autowired都没法用


所以在真实项目开发中我们往往需要一个IOC容器的引用,然后通过该引用随时随地的获取IOC容器中具体的bean对象,如:3.2中的Utils。


3.2 ApplicationContextUtils开发

package com.nrsc.elegant.util;

import com.nrsc.elegant.enums.ResultEnum;
import com.nrsc.elegant.exception.ElegantCheckedException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/***
 * @author : Sun Chuan
 * @date : 2019/11/19 15:08
 * Description: 通过静态方法获取IOC容器中bean实例的方法
 */
@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    /***
     * spring启动后会将IOC容器的引用赋值给application 
     * 静态变量不会被JVM回收,
     * 所以可以通过静态方法getBeanByType 和 getBeanByName随时获取项目中IOC容器内的bean
     */
    private static ApplicationContext applicationContext;

    private ApplicationContextUtils() {
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    /***
     * 从IOC容器中根据类型拿bean实例
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T getBeanByType(Class<T> clazz) throws ElegantCheckedException {
        if (applicationContext == null) {
            throw new ElegantCheckedException(ResultEnum.FAILURE);
        }

        return applicationContext.getBean(clazz);
    }

    /***
     * 从IOC容器中根据beanName拿bean实例
     * @param beanName
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T getBeanByName(String beanName) throws ElegantCheckedException {
        if (applicationContext == null) {
            throw new ElegantCheckedException(ResultEnum.FAILURE);
        }
        return (T) applicationContext.getBean(beanName);
    }
}

4 MessageSource和MessageSourceAware使用介绍

源码地址:
纯spring版: https://github.com/nieandsun/spring-study
springboot版:https://github.com/nieandsun/NRSC-STUDY

对这个Aware印象还是比较深刻的,因为很久之前做过一个安哥拉的项目,项目需要进行葡萄牙语、英语和中文的切换,当时进行标签国际化就用到了它。这里简单介绍一下在spring环境下MessageSourceAware的使用方式。


4.1 实现MessageSourceAware接口使用姿势

使用场景 :项目启动时不同环境加载不同的配置。

4.1.1代码开发

  • 首先要将ResourceBundleMessageSource注入到IOC容器
package com.nrsc.springstudy.c072_bean_life_cycle.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
@ComponentScan(value = "com.nrsc.springstudy.c072_bean_life_cycle")
public class C072Config {
    /***
     * 向IOC容器中注入ResourceBundleMessageSource
     * 该类用来确定properties的位置、设置编码格式等
     * 注意 : spring规定这个bean的name必须叫----> messageSource
     *
     * @return
     */
    @Bean(value = "messageSource")
    public ResourceBundleMessageSource resourceBundleMessageSource() {
        ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
        //设置properties的路径---注意最后一个messages不能少,它指的是properties文件的前缀
        resourceBundleMessageSource.setBasename("i18/messages/messages");
        resourceBundleMessageSource.setDefaultEncoding("utf-8");
        return resourceBundleMessageSource;
    }
}
  • 接下来需要在指定的位置i18/messages文件夹下建立properties文件

在这里插入图片描述

  • 最后是实现MessageSourceAware 接口,解析标签内容,并进行具体的逻辑处理

这种使用方式的应用场景主要为:项目启动时不同环境加载不同的配置

package com.nrsc.springstudy.c072_bean_life_cycle.beans;

import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.stereotype.Component;

import java.util.Locale;

/**
 * @author : Sun Chuan
 * @date : 2019/11/24 11:13
 * Description:
 */
@Component
public class MessageSourceDemo implements MessageSourceAware {
    public void setMessageSource(MessageSource messageSource) {
        String aaa = messageSource.getMessage("hello", null, Locale.getDefault());
        String bbb = messageSource.getMessage("hello", null, Locale.CHINA);
        String ccc = messageSource.getMessage("hello", null, Locale.US);
        System.err.println(aaa);
        System.err.println(bbb);
        System.err.println(ccc);
    }
}

4.1.2 测试

启动项目,可以发现已经解析到了不同properties文件里hello对应的值
在这里插入图片描述

4.2 通过@Autowired注解注入MessageSource使用姿势

使用场景: 使用注入MessageSource的方式,可以直接获取配置文件里key对应的value,这种情况下使用场景就可以自己发挥了。
如有如下Controller:

4.2.1 代码开发

代码在https://github.com/nieandsun/NRSC-STUDY

ackage com.nrsc.elegant.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Locale;

/**
 * @author : Sun Chuan
 * @date : 2019/11/24 12:32
 * Description:
 */
@RestController
public class MessageSourceTestController {

    @Autowired
    private MessageSource messageSource;

    @GetMapping("/")
    public String justTest(String lang) {
        //获取项目服务器所在的国家
        //Locale locale = LocaleContextHolder.getLocale();

        Locale locale = null;
        switch (lang) {
            case "en_US":
                locale = Locale.US;
                break;
            case "zh_CN":
                locale = Locale.CHINA;
                break;
            default:
                locale = Locale.CHINA;
        }
        //  Locale.forLanguageTag(langs)
        String hello = messageSource.getMessage("hello", null, locale);
        return hello;
    }
}

4.2.2 测试

我们可以通过传入不同的参数来获取到不同的值,测试结果如下:
在这里插入图片描述

发布了189 篇原创文章 · 获赞 187 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/103219498