Spring@Autowired注解和静态⽅法、静态变量的初始化顺序
以及PropertyS。。。
问题1:加载顺序问题:
conf.properites配置如下:
fetchJobsSchedule=0 25 0 * * ?
updateJobsSchedule=0 12 17 * * ?
java代码配置如下:
@Component
@PropertySource("classpath:conf.properties")
public class FetchStockSchedule {
private static Logger logger = Logger("info");
@Value("${fetchJobsSchedule}")
private static String fetchJobsSchedule;
@Value("${updateJobsSchedule}")
private static String updateJobsSchedule;
static{
System.out.println("----fetchJobsSchedule:"+fetchJobsSchedule+"------------");
System.out.println("----updateJobsSchedule:"+updateJobsSchedule+"------------");
}
启动项⽬ 加载 static{ ... } 静态代码块输出如下:
D:\softwareIntall\java\jdk1.8.0_144\ -  ......
start
-
---fetchJobsSchedule:null------------
----updateJobsSchedule:null------------
值为null 原因:
@Value @Autowired 等Spring 的注解的注⼊时机 晚于 java static 的加载
关于实例变量与构造⽅法的初始化顺序问题,查询相关资料得知:
1、Java类会先执⾏构造⽅法,然后再给注解了@Value  的属性注⼊值,所以在执⾏静态代码块的时候,就会为null。
2、java 及Spring 初始化顺序:java静态属性/静态代码块(根据声明的先后顺序加载)、构造代码块、 构造⽅法(即:spring创建FetchStockSchedule的实例 交给Spring 管理)、@Value/@ AutoWired/@Resouce 等注解 的成员变量等赋值。
总结:Java变量的初始化顺序为:静态变量或静态语句块(按声明顺序)–>⾮静态变量或构造代码块(按声明顺序)–>构造⽅法–
>@Value/@Autowired等注解
解决:去掉静态代码块,变量改为⾮静态成员变量 (如果只去掉静态代码块,静态成员变量还是赋值失败),
使⽤构造器注⼊的⽅法,明确了成员变量的加载顺序,这样就可以初始化 categoryList 。如下
1.    private CategoryMapper categoryMapper;
2. private List<Category> categoryList;
3.
4. @Autowired
5. public CategoryServiceImpl(CategoryMapper categoryMapper) {
6. this.categoryMapper = categoryMapper;
7. this.categoryList = categoryMapper.selectByExample(new CategoryExample());
8. }
9.
问题2:注⼊properites 属性失败(切记配置PropertySourcesPlaceholderConfigurer.class)
spring 容器启动初始化类:
public class Startup {
private static  Logger logger = Logger(Startup.class);
private static ApplicationContext factory;
private static void loadSpringContext() {
factory = new AnnotationConfigApplicationContext(AppContext.class);
}
public static void main(String[] args)
{
//加载spring
System.out.println("start");
loadSpringContext();
logger.info(" schedule start  ");
}
}
注解配置类:该类中需要配置 读取property⽂件的PropertySourcesPlaceholderConfigurer.class(代码中注释掉的地⽅)
@Configuration
@ComponentScan(basePackages={"st"})
@EnableScheduling
public class AppContext {
/*@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}*/
}
使⽤ @PropertySource注解需要注意以下⼏个地⽅:
1 、使⽤注解需要将类申明被扫描为⼀个bean,可以使⽤@Component 注解
2、@PropertySource(value = "classpath:properties/config_userbean.properties",ignoreResourceNotFound = true) 表⽰注⼊配置⽂件,并且忽略配置⽂件不存在的异常
3、必须返回⼀个 PropertySourcesPlaceholderConfigurer 的bean,否则,会不能识别@Value("${userBean.name}") 注解中的${userBean.name}指向的value,⽽会注⼊${userBean.name}的字符串,返回 PropertySourcesPlaceholderConfigurer 的⽅法,使⽤@Bean注解,表⽰返回的是个bean
为什么要返回⼀个 PropertySourcesPlaceholderConfigurer 的bean呢?让我们来看看源码吧.
PS:因为前⾯本⼈对 PropertySourcesPlaceholderConfigurer 理解有误,导致下⾯解释的模棱两可,因为spring是通过
PropertySourcesPlaceholderConfigurer 内locations来查属性⽂件,然后在根据注解将匹配的属性set进去,⽽下⾯的注释解释,是表⽰⽤注解可以做⼀些什么操作..
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport
implements EnvironmentAware {
/**
* {@value} is the name given to the {@link PropertySource} for the set of
* {@linkplain #mergeProperties() merged properties} supplied to this configurer.
*/
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
/**
* {@value} is the name given to the {@link PropertySource} that wraps the
* {@linkplain #setEnvironment environment} supplied to this configurer.
*/
public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";
private MutablePropertySources propertySources;
private PropertySources appliedPropertySources;
private Environment environment;
下⾯代码省略.....
上⾯源码,并没能看出为什么⼀定要返回这个bean,那么我看就看看他的⽗类 PlaceholderConfigurerSupport 吧.以下是⽗类的源码
/**
* Abstract base class for property resource configurers that resolve placeholders
* in bean definition property values. Implementations <em>pull</em> values from a
* properties file or other {@linkplain nv.PropertySource
* property source} into bean definitions.
*
* <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
*
*<pre class="code">${...}</pre>
*
* Example XML bean definition:
*
*<pre class="code">{@code
*<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
*    <property name="driverClassName" value="}${driver}{@code "/>
*    <property name="url" value="jdbc:}${dbname}{@code "/>
*</bean>
*}</pre>
*
* Example properties file:
* Example properties file:
*
* <pre class="code"> sql.jdbc.Driver
* dbname=mysql:mydb</pre>
*
* Annotated bean definitions may take advantage of property replacement using
* the {@link org.springframework.beans.factory.annotation.Value @Value} annotation:
*
*<pre class="code">@Value("${person.age}")</pre>
*
* Implementations check simple property values, lists, maps, props, and bean names
* in bean references. Furthermore, placeholder values can also cross-reference
* other placeholders, like:
*
*<pre class="code">rootPath=myrootdir
*subPath=${rootPath}/subdir</pre>
*
* In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
* filling in of explicit placeholders in bean definitions.
*
* <p>If a configurer cannot resolve a placeholder, a {@link BeanDefinitionStoreException} * will be thrown. If you want to check against multiple properties files, specify multiple
* resources via the {@link #setLocations locations} property. You can also define multiple  * configurers, each with its <em>own</em> placeholder syntax. Use {@link
* #ignoreUnresolvablePlaceholders} to intentionally suppress throwing an exception if a  * placeholde
r cannot be resolved.
*
* <p>Default property values can be defined globally for each configurer instance
* via the {@link #setProperties properties} property, or on a property-by-property basis  * using the default value separator which is {@code ":"} by default and
* customizable via {@link #setValueSeparator(String)}.
*
* <p>Example XML property with default value:
*
*<pre class="code">{@code
*  <property name="url" value="jdbc:}${dbname:defaultdb}{@code "/>
*}</pre>
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see PropertyPlaceholderConfigurer
* @see t.support.PropertySourcesPlaceholderConfigurer
*/
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer      implements BeanNameAware, BeanFactoryAware {
/** Default placeholder prefix: {@value} */
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
/** Default placeholder suffix: {@value} */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
/** Default value separator: {@value} */
public static final String DEFAULT_VALUE_SEPARATOR = ":";
/** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;
/** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
protected boolean ignoreUnresolvablePlaceholders = false;
protected String nullValue;
private BeanFactory beanFactory;
private String beanName;
类注释表⽰的是,该类所起的作⽤,替代了xml⽂件的哪些操作,我们只需要看下⾯定义的⼀个常量注解就能⼤概知道,为什么需要返回这么⼀个bean了.
类注释上有这么⼀句话:表⽰可以⽤带注释的bean,可以利⽤属性符号进⾏替换
* Annotated bean definitions may take advantage of property replacement using
* the {@link org.springframework.beans.factory.annotation.Value @Value} annotation:
*
*<pre class="code">@Value("${person.age}")</pre>
属性注释:
/** Default placeholder prefix: {@value} */
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
/** Default placeholder suffix: {@value} */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
/** Default value separator: {@value} */
public static final String DEFAULT_VALUE_SEPARATOR = ":";resource和autowired注解的区别
/** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;
/** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
protected boolean ignoreUnresolvablePlaceholders = false;
从上⾯注解可以发现,使⽤的 默认前缀是:  '${',  ⽽后缀是:  '}' ,默认的分隔符是 ':', 但是set⽅法可以替换掉默认的分隔符,
⽽ ignoreUnresolvablePlaceholders 默认为 false,表⽰会开启配置⽂件不存在,抛出异常的错误.
从上⾯就能看出这个bean所起的作⽤,就是将@propertySource注解的bean注⼊属性的作⽤,如果没有该bean,则不能解析${}符号.
在spring 4.0以后,spring增加了@PropertySources 注解,下⾯是源码

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。