创建 bean 的过程中有多个可以自定义的扩展点,以便在 bean 的生命周期中执行自定义操作,以下是在整个生命周期内,可以自定义的点和场景举例
bean定义注册后处理器,允许你在 Spring 容器初始化之前修改或注册 bean 定义。你可以实现这个接口来自定义 bean 的注册
注入
public class MyBeanDefinitionRegistryPostProcessor
implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
AbstractApplicationContext
方法refresh
调用 bean工厂后置处理器:invokeBeanFactoryPostProcessors
,此时bean工厂ConfigurableListableBeanFactory
已经实例化完成PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())
;while (reiterate) {
reiterate = false;
//根据BeanDefinitionRegistryPostProcessor这个class类型得到postProcessorNames,
看到没,此时就得到了我们的bean name
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName,
BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//这里反射调用的
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
//这里调用 invokeBeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
}
invokeBeanDefinitionRegistryPostProcessors
调用private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
//这里调用postProcessBeanDefinitionRegistry
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}
至此初始化调用流程分析完毕
对BeanDefinitionRegistry
的一些操作,可以动态增删bean
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(MyBean1.class);
//注册bean
registry.registerBeanDefinition("myBean", genericBeanDefinition);
//删除bean,前提存在
if(registry.containsBeanDefinition("beanName")){
registry.removeBeanDefinition("beanName");
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface CustomComponent {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
TypeFilter filter = new AnnotationTypeFilter(CustomComponent.class);
scanner.addIncludeFilter(filter);
// 扫描指定包
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("org.example.bean")) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
ClassUtils.resolveClassName(Objects.requireNonNull(beanDefinition.getBeanClassName()), ClassUtils.getDefaultClassLoader()));
registry.registerBeanDefinition(beanDefinition.getBeanClassName(), builder.getBeanDefinition());
}
}
自定义包下,注解为CustomComponent
的类都会被注册到bean中
对ConfigurableListableBeanFactory
的一些操作,这个就比较丰富
以下是使用场景举例:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerSingleton("myBean1",new MyBean1());
}
BeanPostProcessor 是bean在初始化前后的拦截器,创建多少bean 拦截多少次,可以通过postProcessBeanFactory
,动态把拦截器添加进去
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerSingleton("myBean1",new MyBean1());
beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
}
MyBeanPostProcessor 定义如下
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("开始注册:" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("注册完成:" + beanName);
return bean;
}
}
什么意思,就是可以给自定义的属性进行转换,将字符串值转换为特定类型的属性值。
看个场景就明白 了
bean为User的对象有个属性是private Address address;
Address 里边也有自己的属性,如下:
private String address1;
private String address2;
private String address3;
我在注入bean的时候,如果传输的是个字符串或者其他乱七八糟的格式,反正不是Address,我该如下转换呢?
如下bean配置,address给的是河南-郑州-高新区
这显然不是对象,那我们就可以利用自定义转换器来进行转换
AddressEditor
要继承PropertyEditorSupport
,重写方法setAsText
其实这里得到的就是以上的河南-郑州-高新区
字符串,我们手动转换,最后调用setValue
封装进去即可public class AddressEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] arrs = text.split("-");
Address address = new Address();
address.setAddress1(arrs[0]);
address.setAddress2(arrs[1]);
address.setAddress3(arrs[2]);
super.setValue(address);
}
}
AddressEditor
肯定需要注册呀,怎么注册?新建个自定义转换注册器呗,实现PropertyEditorRegistrar
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Address.class, new AddressEditor());
}
}
postProcessBeanFactory
方法的 把注册器加进去public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.addPropertyEditorRegistrar(new CustomEditorRegistrar());
}
执行后,bean的Address就是我们转换后的值
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 修改属性
BeanDefinition user = beanFactory.getBeanDefinition("user");
MutablePropertyValues propertyValues = user.getPropertyValues();
propertyValues.addPropertyValue("id","123456");
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 修改属性
BeanDefinition bd = beanFactory.getBeanDefinition("user");
//修改初始方法、是否为单例,等其他属性
bd.setInitMethodName("test2");
}
用于创建和配置对象实例。它允许你将对象的创建和配置逻辑封装在一个独立的类中
public class MyBeanFactory implements FactoryBean {
@Override
public User getObject() throws Exception {
// 在这里可以编写创建和配置 MyBean 实例的逻辑
return new User();
}
@Override
public Class getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true; // 这里可以指定对象是否是单例
}
}
这样也能创建bean
bean 实现 InitializingBean
重写方法afterPropertiesSet
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
bean完成初始化(还未实例化)之后调用,类AbstractApplicationContext
refresh 你应该不会陌生,此方法执行到
finishBeanFactoryInitialization(beanFactory);
带着问题来看bean的实例化,并知道在何时执行的以上afterPropertiesSet
DefaultListableBeanFactory
方法preInstantiateSingletons
简化代码:
public void preInstantiateSingletons() throws BeansException {
//beanDefinitionNames 你应该不陌生,这就是储存所有bean name 的一个list
List beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
//就是根据bean 名称 实例化 bean
getBean(beanName);
}
}
以上代码就是循环bean名称,然后实例化
doGetBean
此方法就是根据bean name得到成员变量mergedBeanDefinitions
得到bean的元数据信息,也是个map,里边储存的是RootBeanDefinition
他里边就储存了你在xml中定义的bean属性信息AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
getInstantiationStrategy
会得到实例化策略类,这里是SimpleInstantiationStrategy
,代码就来到了这里,这里没啥好讲的,就是得到反射类Constructor
然后根据 .class 创建,具体创建使用的是工具类BeanUtils.instantiateClass(constructorToUse)
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
if (!bd.hasMethodOverrides()) {
Constructor constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class clazz = bd.getBeanClass();
constructorToUse = clazz.getDeclaredConstructor();
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
类Constructor
用法:
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
// 使用构造函数创建对象
Person person = constructor.newInstance("Alice", 25);
BeanWrapper
对象,他是spring提供的一个bean工具类,用于方便地访问和操作 bean 对象的属性具体用法如下:
public static void main(String[] args) {
// 创建一个简单的对象
Person person = new Person();
// 使用 BeanWrapper 包装这个对象
BeanWrapper wrapper = new BeanWrapperImpl(person);
// 设置属性值
wrapper.setPropertyValue("name", "Alice");
wrapper.setPropertyValue("age", 25);
// 获取属性值
String name = (String) wrapper.getPropertyValue("name");
int age = (int) wrapper.getPropertyValue("age");
System.out.println("Name: " + name);
System.out.println("Age: " + age);
//获取对象
Object bean = wrapper.getWrappedInstance();
}
到此,bean实例化完成,最终返回一个bean包装类BeanWrapper
回到最初,刚刚只有bean name和RootBeanDefinition
如何关联上BeanWrapper
的?
doCreateBean
关联代码,mbd 就是RootBeanDefinition
对象,getWrappedClass
就是获取 bean的classClass beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
doCreateBean
调用initializeBean
调用invokeInitMethods
,简化代码如protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
afterPropertiesSet
关键代码,啥意思,bean满足继承了InitializingBean
,就调用mbd.getInitMethodName()
mbd 就是RootBeanDefinition
,getInitMethodName
就是你在xml中定义的初始化方法,xml配置如下:public void test(){
System.out.println("初始化");
}
init-method 定义的方法,如果他有长度,而且方法名不是afterPropertiesSet
而且不是mbd.isExternallyManagedInitMethod(initMethodName)
这个是什么意思?这个引申出另一个概念了:待续
然后利用反射执行我们定义的初始化方法
afterPropertiesSet
是在初始化bean和实例化之后,调用的,在他执行之后才会调用其他xml定义的init-method
init-method
只接受一个无参的初始化方法