文章目录
1 前言
上篇文章《ApplicationContextAwareProcessor源码解析 + Aware接口简介》简单地介绍了Aware接口,本篇文章将介绍一下Aware的使用方法,由于spring中的Aware众多,这里仅仅抛砖引玉,本篇文章会介绍如下几个Aware:
- BeanNameAware — 获取当前bean在IOC容器中的名字
- EmbeddedValueResolverAware — el表达式解析原理
- ApplicationContextAware — 工作中用到
- MessageSourceAware — 工作中用到
下面对其进行一一介绍。
2 BeanNameAware和EmbeddedValueResolverAware使用简介
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在工作中的使用
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 测试
我们可以通过传入不同的参数来获取到不同的值,测试结果如下: