问题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.getLogger("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\bin\java.exe -  ......
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等注解

解决:去掉静态代码块,变量改为非静态成员变量 (如果只去掉静态代码块,静态成员变量还是赋值失败),

对于这种需要提前初始换 成员变量的情况可以采用如下方式(https://blog.csdn.net/g_drive/article/details/80026200)

使用构造器注入的方法,明确了成员变量的加载顺序,这样就可以初始化 categoryList 。如下

 
  private CategoryMapper categoryMapper;private List<Category> categoryList;@Autowiredpublic CategoryServiceImpl(CategoryMapper categoryMapper) {this.categoryMapper = categoryMapper;this.categoryList = categoryMapper.selectByExample(new CategoryExample());}

问题2:注入properites 属性失败(切记配置PropertySourcesPlaceholderConfigurer.class)

spring 容器启动初始化类:

public class Startup {private static   Logger logger = LoggerFactory.getLogger(Startup.class);private static ApplicationContext factory;private static void loadSpringContext() {factory = new AnnotationConfigApplicationContext(AppContext.class);}public static void main(String[] args){//加载springSystem.out.println("start");loadSpringContext();logger.info(" schedule start  ");}
}

注解配置类:该类中需要配置 读取property文件的PropertySourcesPlaceholderConfigurer.class(代码中注释掉的地方)

@Configuration
@ComponentScan(basePackages={"com.wanner.test"})
@EnableScheduling
public class AppContext {/*@Beanpublic 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 PlaceholderConfigurerSupportimplements 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 org.springframework.core.env.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:** <pre class="code"> driver=com.mysql.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* placeholder 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 org.springframework.context.support.PropertySourcesPlaceholderConfigurer*/
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurerimplements 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 = ":";/** 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 注解,下面是源码

/**
 * Container annotation that aggregates several {@link PropertySource} annotations.
 *
 * <p>Can be used natively, declaring several nested {@link PropertySource} annotations.
 * Can also be used in conjunction with Java 8's support for <em>repeatable annotations</em>,
 * where {@link PropertySource} can simply be declared several times on the same
 * {@linkplain ElementType#TYPE type}, implicitly generating this container annotation.
 *
 * @author Phillip Webb
 * @since 4.0
 * @see PropertySource
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertySources {
   PropertySource[] value();
}
 
从源码的注释,可以看到自4.0以后,@PropertySources注解,可以使用多个@PropertySource注解,代码如下:
@PropertySources(
      {
            @PropertySource("classpath:properties/config_userbean.properties"),
            @PropertySource("classpath:properties/config_mysql.properties")
      }
)
 
有时候使用@PropertySource 注解会报 找不到这个注解的错误,但是spring确实是3.1以上版本,而且并不影响项目的使用,这样的话,可以使用@propertySources 注解嵌套@propertySource注解,这样就不会报错了

补充:

//执行一个class 的mian 方法时执行顺序:(优先级从高到低。)静态代码块>mian方法>构造代码块>构造方法。

其中静态代码块只执行一次。构造代码块在每次创建对象是都会执行。

普通代码块:在方法或语句中出现的{}就称为普通代码块。普通代码块和一般的语句执行顺序由他们在代码中出现的次序决定--“先出现先执行”
构造块:直接在类中定义且没有加static关键字的代码块称为{}构造代码块。构造代码块在创建对象时被调用,每次创建对象都会被调用,并且构造代码块的执行次序优先于类构造函数。
静态代码块:在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。如果类中包含多个静态代码块,那么将按照"先定义的代码先执行,后定义的代码后执行"。
注意:1 静态代码块不能存在于任何方法体内。2 静态代码块不能直接访问 非静态变量和方法,可通过类的实例对象来访问。

  1. @Autowired

  2. CategoryMapper categoryMapper;

java 和 spring加载顺序问题相关推荐

  1. java中类的加载顺序

    java中类加载顺序: 1)静态代码块只执行一次:静态代码块首先被初始化 2)构造代码块在每次创建对象都会执行:构造函数都是最后执行的. 3)按照父子类继承关系进行初始化,先执行父类的初始化: 4)程 ...

  2. JAVA Web.xml 加载顺序

    web.xml加载过程(步骤): 1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener> ...

  3. spring加载顺序

    因为项目需求,要实现自定义注解然后通过spring扫描注解并放入缓存,我想到了BeanDefinitionRegistryPostProcessor接口,通过实现 BeanDefinitionRegi ...

  4. java 初始化的加载顺序问题

    总结一下java里面关于初始化的加载顺序问题: 考虑有一个基类和一个子类的情况 那么,当实例化一个子类的对象或者访问子类的静态域或静态方法时,会进行类的加载. 1)完成基类的static域和stati ...

  5. java 类的加载顺序

    类的加载顺序 public class ClassA {public static ClassA classa = new ClassA();static{System.out.println(&qu ...

  6. java类spring加载_spring的加载机制?

    1,今天面试官问我spring的加载机制有哪些---这么"抽象"的问题作为一个十多年经验的自己写过MVC,IOC,ORM, 等各种中间件小框架的开发人员也回答不出来~ 确切的说是无 ...

  7. java 中类的加载顺序

    1.虚拟机在首次加载Java类时,会对静态初始化块.静态成员变量.静态方法进行一次初始化  2.只有在调用new方法时才会创建类的实例  3.类实例创建过程:按照父子继承关系进行初始化,首先执行父类的 ...

  8. java类的加载顺序题目_Java 类的加载顺序(题)

    引例 public class A extends B { public int a = 100; public A() { super(); System.out.println(a); a = 2 ...

  9. java中类的加载顺序介绍(ClassLoader)

    1.ClassNotFoundExcetpion 我们在开发中,经常可以遇见java.lang.ClassNotFoundExcetpion这个异常,今天我就来总结一下这个问题.对于这个异常,它实质涉 ...

最新文章

  1. 【网址收藏】Docker中ADD和COPY的区别
  2. mysql global temporary table_【转】MySQL Temporary Table相关问题的探究
  3. MySQL触发器介绍
  4. 如何自动判断域名是否被微信拦截 被微信屏蔽的域名网址如何正常打开使用
  5. Verilog HDL中位运算符、逻辑运算符和缩减运算符的区别
  6. mysql count里面能加条件吗_select count(1) 和 count(*),哪个性能更好?
  7. 年薪十万的王者荣耀,LOL游戏模型师的工作是这样的|附50G资料
  8. QT每日一练day8:信号与槽机制
  9. 车借给朋友好几次,满油的车每次还回来都是没油了,我觉得心里有些不舒服是我太计较吗?
  10. java 语法 —— final
  11. vShpere可用性之五HA安装及配置
  12. 反向传播算法BP公式推导
  13. 应用ImageJ对荧光图片进行半定量分析
  14. 金蝶KIS专业版V14.1即时库存查询表添加字段条形码|商品描述|最低最高存量
  15. 《数据清洗》 第六章 数据转换
  16. Android布局优化之TextView、ImageView合二为一
  17. 报错 | Error: EPERM: operation not permitted, unlink ‘C:\Users\Admin\practice\node_modules\css-loader
  18. 8汉化 netreflector_Reflector 8中文版
  19. 软件测试课堂笔记之语句覆盖,判定覆盖,条件覆盖,判定/条件覆盖,在eclipse上新建测试用例
  20. 摄影基础之【**相机画幅、人眼视角范围**】

热门文章

  1. 企业管理好书推荐,管理类书籍看这些就够了
  2. C++ STL 之队列(先进先出) queue 详解
  3. 人生虽然很艰难,但所有的付出都有回报
  4. jenkins allure、企业微信配置
  5. 优雅的使用百度搜索,安装广告过滤插件
  6. cs213n课程笔记
  7. c语言车辆维修信息管理系统,汽车销售管理系统 C语言版及汽车维修管理制度汇编(45页)-原创力文档...
  8. Flink JDBCOutputFormat
  9. ABP教程-给项目添加SwaggerUI,生成动态webapi
  10. 朴素贝叶斯 python