@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文件
- <bean id="aaa" class="com.dingwang.Test.Aaa" init-method="init">
- <constructor-arg name="name" value="ddd"></constructor-arg>
- </bean>
2.java文件
- public Aaa(String name) {
- LOGGER.warn("--------------------Aaa-----------------Aaa");
- this.setName(name);
- }
- public void init() {
- LOGGER.warn("--------------------Aaa-----------------init");
- }
- /*
- * (non-Javadoc)
- * @see
- * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
- */
- @Override
- public void afterPropertiesSet() throws Exception {
- LOGGER.warn("--------------------Aaa-----------------afterPropertiesSet");
- }
3.执行日志
- 10:44:54.116 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean ‘aaa‘
- 10:44:54.157 [main] WARN com.dingwang.Test.Aaa - --------------------Aaa-----------------Aaa
- 10:44:54.159 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean ‘aaa‘ to allow for resolving potential circular references
- 10:44:54.171 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name ‘aaa‘
- 10:44:54.172 [main] WARN com.dingwang.Test.Aaa - --------------------Aaa-----------------afterPropertiesSet
- 10:44:54.172 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking init method ‘init‘ on bean with name ‘aaa‘
- 10:44:54.172 [main] WARN com.dingwang.Test.Aaa - --------------------Aaa-----------------init
- 10:44:54.173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean ‘aaa‘
4.结论
执行顺序:构造函数>afterPropertiesSet>init-method
Person类
- public class Person {
- private int i = 0;
- public Person(){
- System.out.println("实例化一个对象");
- }
- public void init(){
- System.out.println("调用初始化方法....");
- }
- public void destory222(){
- System.out.println("调用销毁化方法....");
- }
- }
applicationContext.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
- <!-- 配置初始化方法和销毁方法,但是如果要销毁方法生效scope="singleton" -->
- <bean id="person" class="com.xxc.initAndDestory.domain.Person" scope="singleton" lazy-init="false" init-method="init" destroy-method="destory"></bean>
- </beans>
测试类:
- public class Test {
- public static void main(String[] args) {
- //如果要调用销毁方法必须用子类来声明,而不是ApplicationContext,因为ApplicationContext没有close()
- ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxc/initAndDestory/applicationContext.xml");
- Person p1 = (Person)ac.getBean("person");
- Person p2 = (Person)ac.getBean("person");
- ac.close();
- }
- }
如果用注解方式配置:
applicationContext.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-2.5.xsd">
- <context:annotation-config/>
- <!-- scope默认是 prototype:getBean()一次创建一个实例-->
- <bean id="person" class="com.xxc.initAndDestory.domain.Person"></bean>
- </beans>
Person类
- public class Person {
- private int i = 0;
- public Person(){
- System.out.println("实例化一个对象");
- }
- @PostConstruct //初始化方法的注解方式 等同与init-method=init
- public void init(){
- System.out.println("调用初始化方法....");
- }
- @PreDestroy //销毁方法的注解方式 等同于destory-method=destory222
- public void destory(){
- System.out.println("调用销毁化方法....");
- }
- }
以上是关于@Value 和 @Bean 的执行顺序问题的主要内容,如果未能解决你的问题,请参考以下文章
关于Spring Bean的生命周期中几个常用方法(@PostConstruct@PreDestroy 等)的执行顺序
Java类的各种成员初始化顺序如:父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺