@Value 和 @Bean 的执行顺序问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@Value 和 @Bean 的执行顺序问题相关的知识,希望对你有一定的参考价值。

参考技术A 本篇内容主要讲解 “如何理解 @Value 和 @Bean 的执行顺序问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让我来带大家学习“如何理解 @Value 和 @Bean 的执行顺序问题” 吧!

使用 @Autowired 处理多个同种类型的 bean,出现 @Value 和 @Bean 的执行顺序问题。

Springboot 中使用 @Configruation 和 @Bean 一起将 Bean 注册到 ioc 容器中,而 @Value 常用于将 yml 配置文件中的配置信息注入到类的成员变量中。当 @Configruation、@Bean 和 @Value 出现在同一个类中时,@Bean 会比 @Value 先执行,这会导致当 @Bean 注解的方法中用到 @Value 注解的成员变量时,无法注入(null)的情况。例如在为 Feign 创建配置类,以实现 Feign 的权限验证时,需要将 yml 文件中的用户名和密码注入到配置类的成员变量中,@Bean 注解方法则依赖于用户名和密码产生 Bean 的实例。

解决方法

第一种:

直接在 @Bean 方法的参数上使用 @Value 注入 username 和 password

第二种:

重新写一个用户名和密码的类 AuthConfig,然后用 @AutoWired 通过注入 AuthConfig 的对象来实现用户名和密码的注入,同样要在方法的参数上注入。

这两种方法的思路应该都是利用 Springboot 对依赖关系的解析,当一个类对另一个类有明显依赖关系时,会改变 bean 加载的优先级?待深入研究
此处可以参考,springbean控制加载顺序的文章

首先使用扫描包 + 注解的方式注册 User 类型的不同 bean, 分别是 user、user1, 注册方式如下

该方式得到 User 类型的名为 user 的 bean

UserDao 配置如下:

输出结果如下:

没有加入 @Value 注解时是没有问题的,但是加入了 @Value 之后

再次运行 testWired 方法后

结果输出如下:

为什么会出现这种情况?
一开始,怎么也想不通,查看网上的资料大多数是说 @Bean 和 @Value 有执行顺序这一说法。

为了验证这一说法,做个对比试验

去掉了一个 @Value(“张三”)

问题原因
@Value 和 @Bean 在不同文件下时,@Bean 比 @Value 先执行。这样就回导致 @Bean 注入的值失效。

解决办法
网上说 @Value 和 @Bean 在不同文件下时,@Bean比@Value 先执行, 因此,我做了如下设置

把 User.java 下的 @Value 注解去掉,而是将 @Value 注解放在 @bean 同一文件下

此时再运行测试方式,输出结果如下:

spring bean中构造函数,afterPropertiesSet和init-method的执行顺序

http://blog.csdn.net/super_ccc/article/details/50728529

1.xml文件

 

[html] view plain copy
 
 print?
  1. <bean id="aaa" class="com.dingwang.Test.Aaa" init-method="init">  
  2.         <constructor-arg name="name" value="ddd"></constructor-arg>  
  3.     </bean>  


2.java文件

 

 

[java] view plain copy
 
 print?
  1. public Aaa(String name) {  
  2.        LOGGER.warn("--------------------Aaa-----------------Aaa");  
  3.        this.setName(name);  
  4.    }  
  5.   
  6.    public void init() {  
  7.        LOGGER.warn("--------------------Aaa-----------------init");  
  8.    }  
  9.   
  10.    /* 
  11.     * (non-Javadoc) 
  12.     * @see 
  13.     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 
  14.     */  
  15.    @Override  
  16.    public void afterPropertiesSet() throws Exception {  
  17.        LOGGER.warn("--------------------Aaa-----------------afterPropertiesSet");  
  18.    }  


3.执行日志

 

 

[plain] view plain copy
 
 print?
  1. 10:44:54.116 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean ‘aaa‘  
  2. 10:44:54.157 [main] WARN  com.dingwang.Test.Aaa - --------------------Aaa-----------------Aaa  
  3. 10:44:54.159 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean ‘aaa‘ to allow for resolving potential circular references  
  4. 10:44:54.171 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name ‘aaa‘  
  5. 10:44:54.172 [main] WARN  com.dingwang.Test.Aaa - --------------------Aaa-----------------afterPropertiesSet  
  6. 10:44:54.172 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking init method  ‘init‘ on bean with name ‘aaa‘  
  7. 10:44:54.172 [main] WARN  com.dingwang.Test.Aaa - --------------------Aaa-----------------init  
  8. 10:44:54.173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean ‘aaa‘  


4.结论

 

执行顺序:构造函数>afterPropertiesSet>init-method

 

Person类

 

[java] view plain copy
 
 print?
  1. public class Person {  
  2.     private int i = 0;  
  3.   
  4.     public Person(){  
  5.         System.out.println("实例化一个对象");  
  6.     }  
  7.       
  8.     public void init(){  
  9.         System.out.println("调用初始化方法....");  
  10.     }  
  11.       
  12.     public void destory222(){  
  13.         System.out.println("调用销毁化方法....");  
  14.     }  
  15. }  


applicationContext.xml

 

 

[html] view plain copy
 
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.         xsi:schemaLocation="http://www.springframework.org/schema/beans   
  5.                             http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  6.     <!-- 配置初始化方法和销毁方法,但是如果要销毁方法生效scope="singleton" -->                  
  7.     <bean id="person" class="com.xxc.initAndDestory.domain.Person" scope="singleton" lazy-init="false" init-method="init" destroy-method="destory"></bean>  
  8. </beans>  


测试类:

 

 

[java] view plain copy
 
 print?
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         //如果要调用销毁方法必须用子类来声明,而不是ApplicationContext,因为ApplicationContext没有close()  
  4.         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxc/initAndDestory/applicationContext.xml");  
  5.         Person p1 = (Person)ac.getBean("person");  
  6.         Person p2 = (Person)ac.getBean("person");  
  7.         ac.close();  
  8.     }  
  9. }  

 

 

 

如果用注解方式配置:

applicationContext.xml

 

[html] view plain copy
 
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:context="http://www.springframework.org/schema/context"   
  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans     
  6.                             http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
  7.                             http://www.springframework.org/schema/context     
  8.                             http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
  9.                               
  10.     <context:annotation-config/>   
  11.                               
  12.     <!-- scope默认是 prototype:getBean()一次创建一个实例-->  
  13.     <bean id="person" class="com.xxc.initAndDestory.domain.Person"></bean>  
  14. </beans>  


Person类

 

 

[java] view plain copy
 
 print?
    1. public class Person {  
    2.     private int i = 0;  
    3.   
    4.     public Person(){  
    5.         System.out.println("实例化一个对象");  
    6.     }  
    7.     @PostConstruct //初始化方法的注解方式  等同与init-method=init  
    8.     public void init(){  
    9.         System.out.println("调用初始化方法....");  
    10.     }  
    11.     @PreDestroy //销毁方法的注解方式  等同于destory-method=destory222  
    12.     public void destory(){  
    13.         System.out.println("调用销毁化方法....");  
    14.     }  
    15. }  

以上是关于@Value 和 @Bean 的执行顺序问题的主要内容,如果未能解决你的问题,请参考以下文章

进程管理顺序执行和并发执行

在Spring Bean的生命周期中各方法的执行顺序

关于Spring Bean的生命周期中几个常用方法(@PostConstruct@PreDestroy 等)的执行顺序

Java类的各种成员初始化顺序如:父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺

哪个先执行:@PostConstruct和@Bean的initMethod?

Spring5MVC——启动过程,执行refresh方法的入口