关于BeanDefinitionBuilder的setInitMethodName
来源:3-21 定时任务通用组件封装-5
0x0wh04m1
2020-05-10 23:49:01
老师,您好!首先表示一下肯定,在这部分确实学到很多封装的知识,受益匪浅!
这里有些疑问想提一下,就是在编写ElasticJobConfParser这个类的时候,BeanDefinitionBuilder调用setInitMethodName设置初始化方法的名称为init,然后最后又手动去调用SpringJobScheduler的init方法,这样不是会执行两次init方法吗?
git上ElasticJobConfParser类的源码地址:https://git.imooc.com/class-73/Architect-Stage-5-RabbitMQ/src/master/rabbit-parent/rabbit-task/src/main/java/com/bfxy/rabbit/task/parser/ElasticJobConfParser.java
部分代码
...
// 126行
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(SpringJobScheduler.class);
factory.setInitMethodName("init");
factory.setScope("prototype");
...
SpringJobScheduler scheduler = (SpringJobScheduler)applicationContext.getBean(registerBeanName);
scheduler.init();
// 156行为此我自己写了个简单的demo来验证了这个设想
要放入Spring容器的类
package com.springboot.springbootdemo.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: wh0am1
* @date: 2020/5/10
* @description:
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
public void init() {
System.err.println("------------ init -------------");
System.err.println(id + " : " + name);
}
}实现了ApplicationListener接口的类
package com.springboot.springbootdemo.demo;
import com.springboot.springbootdemo.entity.User;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author: wh0am1
* @date: 2020/5/10
* @description:
*/
@Component
public class BeanDefinitionDemo implements ApplicationListener<ApplicationReadyEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(User.class);
builder.setInitMethodName("init");
builder.setScope("prototype");
builder.addConstructorArgValue(1);
builder.addConstructorArgValue("bean definition");
builder.setLazyInit(false);
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
beanFactory.registerBeanDefinition("user", builder.getBeanDefinition());
User user = applicationContext.getBean("user", User.class);
user.init();
}
}启动后控制台的输出结果

1回答
是的非常感谢小伙伴提出疑问,这个问题首先解释一下getBean方法内部会做一次createbean的init操作,最后的scheduler.init() 确实是可以省略的,不过esjob里面的init是单例模型可以忽略此问题不计,所以我这里显示的init调用也不会有大问题,但是如果非单例情况则需要注意此问题~ ,因为之前生产环境出现过不加载的问题,所以这里我还是显示调用一次,而且当当的esjob解决此问题也是通过单例来屏蔽该问题的发生的(这是早期的一个问题),这就小孩儿没娘。。说来话长了,哈哈 在这里不延伸太细节;
详见1:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法
详见2:com.dangdang.ddframe.job.lite.api.JobScheduler#init
相似问题