Spring中抽象类中使用EmbeddedValueResolverAware和@PostConstruct获取配置文件中的参数值
我的需求:
我有一个 abstract class 中包含了很多子类中需要用到的公共方法和变量,我想在抽象类中
使用@Value获取*.properties中的值。但是@Value必须要在Spring的Bean生命周期管理下才能
使用,比如类被@Controller、@Service、@Component等注解标注。那我就想在抽象类中获取
*.properties中的值,怎么办?
我项目的大概情况:
web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/spring-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
spring-context.xml
<context:component-scan base-package="com.hyxf.amlfetch" /> <context:annotation-config /> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreResourceNotFound" value="true" /> <property name="locations"> <list> <!--<value>classpath*:*.properties</value>--> <--这样也可以,只是感觉不是很明了--> <value>classpath*:config.properties</value> <value>classpath*:jdbc.properties</value> <value>classpath*:log4j.properties</value> </list> </property> </bean>
准备代码:
1、写一个PropertiesUtil工具类,实现EmbeddedValueResolverAware
package com.hyxf.amlfetch.common.util; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.stereotype.Component; import org.springframework.util.StringValueResolver; /** * 获取properties文件中的value的工具类 */ @Component public class PropertiesUtil implements EmbeddedValueResolverAware { private StringValueResolver stringValueResolver; @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { stringValueResolver = resolver; } public String getPropertiesValue(String name){ return stringValueResolver.resolveStringValue(name); } }
2、在需要获取*.properties值的抽象类中引入PropertiesUtil工具类,并使用@PostConstruct注解进行初始化。
package com.hyxf.amlfetch.biz.service.coop; import com.hyxf.amlfetch.common.util.PropertiesUtil; import org.springframework.beans.factory.annotation.Autowired; import com.hyxf.amlfetch.common.util.Logger; import com.hyxf.amlfetch.dao.mapper.aml.OdsT2aBatchMapper; import org.springframework.util.StringUtils; import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.Map; public abstract class AbstractFetchService<T> implements FetchService<T> { protected Logger logger = Logger.getLogger(this.getClass()); @Autowired protected OdsT2aBatchMapper odsT2aBatchMapper; @Autowired private PropertiesUtil propertiesUtil; private static final String DB_READ_NUM_KEY = "each_db_read_num"; private static final String DB_WRITE_NUM_KEY = "each_db_write_num"; private static Map<String, String> dbNum = new HashMap<>(); /** * 索引位置 */ protected static final Integer FROM_INDEX = 0; /** * 加载配置文件的值 * 抽象类不能够使用@Value,在spring容器初始话的时候来获取这个值 */ @PostConstruct public void init() { String eachDbWriteNum = propertiesUtil.getPropertiesValue("${" + DB_WRITE_NUM_KEY + "}"); if(StringUtils.isEmpty(dbNum.get(DB_WRITE_NUM_KEY))) { dbNum.put(DB_WRITE_NUM_KEY, eachDbWriteNum); } String eachDbReadNum = propertiesUtil.getPropertiesValue("${" + DB_READ_NUM_KEY + "}"); if(StringUtils.isEmpty(dbNum.get(DB_READ_NUM_KEY))) { dbNum.put(DB_READ_NUM_KEY, eachDbReadNum); } } public Integer getEachDbWriteNum() { if(StringUtils.isEmpty(dbNum.get(DB_WRITE_NUM_KEY))) { return 0; } return Integer.parseInt(dbNum.get(DB_WRITE_NUM_KEY)); } public Integer getEachDbReadNum() { if(StringUtils.isEmpty(dbNum.get(DB_READ_NUM_KEY))) { return 0; } return Integer.parseInt(dbNum.get(DB_READ_NUM_KEY)); } }
解释一下,为什么这里用了一个static的HashMap,因为这个抽象类有8个子类,其中4个class 和 4个 abstract class
所以在debug的过程中这个被@PostConstruct注解的init()方法在Spring容器启动的时候会运行8次,但是4个class是能通过
propertiesUtil获取到值的,而4个abstract class 是获取不到值的。所以就把第一次获取到的properties中的值用map存下来。
(肯定有更好的方法但是我没有发现,希望大家可以告诉我)