Spring(3)手动注册BeanDefinition

大体思路:

1、选择BeanDefinition的实现类,并实例化BeanDefinition

2、注册BeanDefinition

3、获取Bean,看看是不是正常工作的。

非抽象的实现类主要有三个

1、GenericBeanDefinition,这个也是官方推荐使用的,注释里提到可以动态设置parent bean definition等。

2、RootBeanDefinition,这个跟@Configuration注解有关。
3、ChildBeanDefinition,这个也可以实现设置parent bean definition,不过它是预先定义parent/child关系,官方也不推荐使用了,看注释可以知道,从spring2.5开始

GenericBeanDefinition已经替代ChildBeanDefinition 了。

基于以上思路,我们选择GenericBeanDefinition

public class GenericBeanDefinition extends AbstractBeanDefinition {

    @Nullable
    private String parentName;


    /**
     * Create a new GenericBeanDefinition, to be configured through its bean
     * properties and configuration methods.
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     */
    public GenericBeanDefinition() {
        super();
    }

    /**
     * Create a new GenericBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     */
    public GenericBeanDefinition(BeanDefinition original) {
        super(original);
    }


    @Override
    public void setParentName(@Nullable String parentName) {
        this.parentName = parentName;
    }

    @Override
    @Nullable
    public String getParentName() {
        return this.parentName;
    }


    @Override
    public AbstractBeanDefinition cloneBeanDefinition() {
        return new GenericBeanDefinition(this);
    }

    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof GenericBeanDefinition)) {
            return false;
        }
        GenericBeanDefinition that = (GenericBeanDefinition) other;
        return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
    }

    @Override
    public String toString() {
        if (this.parentName != null) {
            return "Generic bean with parent '" + this.parentName + "': " + super.toString();
        }
        return "Generic bean: " + super.toString();
    }

}

框架里面一般是怎么使用GenericBeanDefinition的呢?

一般是在BeanDefinitionBuilder里面,或者是BeanDefinitionReaderUtils,我记得是这个,由于这个笔记本不好用,简单搜下

 然后就是注册BeanDefinition了

找一个beanFactory,

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

不只实现了ConfigurableListableBeanFactory,还实现了BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {

    /**
     * Register a new bean definition with this registry.
     * Must support RootBeanDefinition and ChildBeanDefinition.
     * @param beanName the name of the bean instance to register
     * @param beanDefinition definition of the bean instance to register
     * @throws BeanDefinitionStoreException if the BeanDefinition is invalid
     * @throws BeanDefinitionOverrideException if there is already a BeanDefinition
     * for the specified bean name and we are not allowed to override it
     * @see GenericBeanDefinition
     * @see RootBeanDefinition
     * @see ChildBeanDefinition
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    ..........

}

所以,我们只要调用这个beanFactory的注册方法即可。

生成beanName

BeanNameGenerator接口,有两个实现类

public interface BeanNameGenerator {

    /**
     * Generate a bean name for the given bean definition.
     * @param definition the bean definition to generate a name for
     * @param registry the bean definition registry that the given definition
     * is supposed to be registered with
     * @return the generated bean name
     */
    String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);

}

 AnnatationBeanNameGenerator就是我们平时使用的注解方式@Autowired,的一个这样的格式,而默认的beanName则是,类名称+#+0(com.spring.learn.service.impl.TestServiceImpl#0)这样的。

bean之间的依赖

通过constructor,或者property方式注入

之前不是说过BeanDefinition接口里面有两个参数,一个是关于构造函数,一个是关于属性set方法注入的。

 

 构造器注入代码

 GenericBeanDefinition controllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.
                genericBeanDefinition(TestControllerWithConstructor.class)
                .addConstructorArgValue("controller name is TestController")
                .addConstructorArgReference(testServiceName)
                .getBeanDefinition();

属性值注入代码

        GenericBeanDefinition propertyControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
                .genericBeanDefinition(TestControllerWithProperty.class)
                .addPropertyValue("name","name is property controller")
                .addPropertyReference("testService",testServiceName).getBeanDefinition();

完成注入代码:

 public static void main(String[] args) {
//        SpringApplication.run(SpringLearnApplication.class, args);
        //创建一个工厂来
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //创建beanDefinition
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.genericBeanDefinition(TestServiceImpl.class)
                .getBeanDefinition();
        //创建beanDefinition Name
        String testServiceName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(beanDefinition,beanFactory);
        //注入到spring 工厂里
        beanFactory.registerBeanDefinition(testServiceName,beanDefinition);

        //创建controller,这个builder模式里边,要调用constructor的方法
        GenericBeanDefinition controllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.
                genericBeanDefinition(TestControllerWithConstructor.class)
                .addConstructorArgValue("controller name is TestController")
                .addConstructorArgReference(testServiceName)
                .getBeanDefinition();
        String controllerBeanName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(controllerBeanDefinition,beanFactory);
        beanFactory.registerBeanDefinition(controllerBeanName,controllerBeanDefinition);

        //---------------------------------------------
        //注入之后,再取出来,将controller里面service和 spring里面的service作对比是不是一样的。
        TestControllerWithConstructor testController = (TestControllerWithConstructor) beanFactory.getBean(controllerBeanName);
        TestService testService = (TestService) beanFactory.getBean(testServiceName);
        Assert.isTrue(testController.getTestService()==testService,"他们不相等,有问题");


        //__________________________________________________
        //这个是通过属性值property注入到DefaultListableBeanFactory
        GenericBeanDefinition propertyControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
                .genericBeanDefinition(TestControllerWithProperty.class)
                .addPropertyValue("name","name is property controller")
                .addPropertyReference("testService",testServiceName).getBeanDefinition();
        String propertyControllerName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(propertyControllerBeanDefinition,beanFactory);
        beanFactory.registerBeanDefinition(propertyControllerName,propertyControllerBeanDefinition);
        //注入进去之后,再取出propertyController
        TestControllerWithProperty propertyController = (TestControllerWithProperty) beanFactory.getBean(propertyControllerName);
        System.out.println(propertyController.getName());
        Assert.isTrue(propertyController.getTestService()==testService,"他们不相等,有问题");

    }

https://www.cnblogs.com/grey-wolf/p/12070377.html

今天就到这了,我去看别的了,

原文地址:https://www.cnblogs.com/fuckingPangzi/p/15738051.html