Spring on bean generation

Time:2021-4-17

Bean generation

  1. First, scan the package. If the @ Component annotation is found, the XX.class A beandefinition will be generated. Based on the properties in beandefinition, a bean object will be created after a modification by the bean factory postprocessor.
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    String SCOPE_SINGLETON = "singleton";
    String SCOPE_PROTOTYPE = "prototype";
    int ROLE_APPLICATION = 0;
    int ROLE_SUPPORT = 1;
    int ROLE_INFRASTRUCTURE = 2;
    void setParentName(@Nullable String var1);
    @Nullable
    String getParentName();
    void setBeanClassName(@Nullable String var1);
    @Nullable
    String getBeanClassName();
    void setScope(@Nullable String var1);
    @Nullable
    String getScope();
    void setLazyInit(boolean var1);
    boolean isLazyInit();
    void setDependsOn(@Nullable String... var1);
    @Nullable
    String[] getDependsOn();
    void setAutowireCandidate(boolean var1);
    boolean isAutowireCandidate();
    void setPrimary(boolean var1);
    boolean isPrimary();
    void setFactoryBeanName(@Nullable String var1);
    @Nullable
    String getFactoryBeanName();
    void setFactoryMethodName(@Nullable String var1);
    @Nullable
    String getFactoryMethodName();
    ConstructorArgumentValues getConstructorArgumentValues();
    default boolean hasConstructorArgumentValues() {
        return !this.getConstructorArgumentValues().isEmpty();
    }
    MutablePropertyValues getPropertyValues();
    default boolean hasPropertyValues() {
        return !this.getPropertyValues().isEmpty();
    }
    boolean isSingleton();
    boolean isPrototype();
    boolean isAbstract();
    int getRole();
    @Nullable
    String getDescription();
    @Nullable
    String getResourceDescription();
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
}
  1. You can also generate an object through @ bean and put it in the spring container.
  2. Factorybean, which has only one object, is a relatively small factory: by implementing the factorybean interface, you can get the object returned by getobject()
import org.springframework.beans.factory.FactoryBean;
public class myfactorybean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new A();
    }

    @Override
    public Class> getObjectType() {
        return A.class;
    }
}

**What about interfaces? How to create**

JDK dynamic proxy utilizes factorybean integration

public class myfactorybean implements FactoryBean {
     Class mapper;

    public myfactorybean(Class mapper) {
        this.mapper = mapper;
    }
    @Override
    public Object getObject() throws Exception {
        //JDK dynamic proxy
        userMapper userMapper = (userMapper) Proxy.getProxyClass(myfactorybean.class.getClassLoader(),
                new Class[]{userMapper.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        if(Object.class.equals(method.getDeclaringClass())){
                            return method.invoke(this,objects);
                        }
                        return null;
                    }
                });
        return userMapper;
    }

    @Override
    public Class> getObjectType() {
        return userMapper.class;
    }
}
//The actual invoke in mybatis
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
    }

What if you need to create a lot of mappers? How to create a factotybean?

//When spring starts, the generated BD is put into the spring container
//We can implement the importbeandefinitionregister and the related logic in the registerbeandefinitions method. In @ import annotation, we can implement the custom bean.
public class factorybeanregister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        ArrayList mappers = new ArrayList < > (); // can be obtained by scanning
        mappers.add(A.class);
        mappers.add(userMapper.class);
        for (Class mapper:mappers){
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
            beanDefinition.setBeanClass(myfactorybean.class);//bean
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper);
            registry.registerBeanDefinition(mapper.getName(),beanDefinition);
        }
    }
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    }
}

How to get mapper by scanning?

Mybatis integrates spring

You can customize an annotation to define the scanned Dao package, and add an import annotation on it to add the required beans to the spring container

@Import(factorybeanregister.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface myscan {
     String value() default "";
}

Then add the annotation @ myscan in the configuration class(“.. Dao “), scan Dao package.

In fact, there is a mapperscan annotation in the mybatis spring jar package. Ma is imported in mapperscan pperScannerRegistrar.class It defines to get the information of the class under the given package path in mapperscan – registerbeandefinitions();

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    public static final Logger LOGGER = LoggerFactory.getLogger(MapperScannerRegistrar.class);

    private ResourceLoader resourceLoader;

    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        // this check is needed in Spring 3.1
        if (resourceLoader != null) {
            scanner.setResourceLoader(resourceLoader);
        }

        Class extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        if (!Annotation.class.equals(annotationClass)) {
            scanner.setAnnotationClass(annotationClass);
        }

        Class> markerInterface = annoAttrs.getClass("markerInterface");
        if (!Class.class.equals(markerInterface)) {
            scanner.setMarkerInterface(markerInterface);
        }

        Class extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
        if (!BeanNameGenerator.class.equals(generatorClass)) {
            scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
        }

        Class extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
        if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
            scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
        }

        scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
        scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

        List basePackages = new ArrayList();
        for (String pkg : annoAttrs.getStringArray("value")) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        for (String pkg : annoAttrs.getStringArray("basePackages")) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        for (Class> clazz : annoAttrs.getClassArray("basePackageClasses")) {
            basePackages.add(ClassUtils.getPackageName(clazz));
        }
        //Priority mapperhelperref > Properties > springboot
        String mapperHelperRef = annoAttrs.getString("mapperHelperRef");
        String[] properties = annoAttrs.getStringArray("properties");
        if (StringUtils.hasText(mapperHelperRef)) {
            scanner.setMapperHelperBeanName(mapperHelperRef);
        } else if (properties != null && properties.length > 0) {
            scanner.setMapperProperties(properties);
        } else {
            try {
                scanner.setMapperProperties(this.environment);
            } catch (Exception e) {
                LOGGER.warn (only in the spring boot environment, general mapper can be configured through the environment (configuration files, environment variables, running parameters, etc.)+
                        "For other environments, please use mapperhelperref or properties parameter in @ mapperscan annotation to configure!"+
                        "If you use tk.mybatis.mapper . session.Configuration  Configure the general mapper, you can ignore the error! ";
            }
        }
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(basePackages));
    }
@Override
    public Set doScan(String... basePackages) {
        Set beanDefinitions = super.doScan(basePackages);
		//The type of BD is the type of the current class
        if (beanDefinitions.isEmpty()) {
            logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        } else {
            processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }
private void processBeanDefinitions(Set beanDefinitions) {
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder holder : beanDefinitions) {
            definition = (GenericBeanDefinition) holder.getBeanDefinition();
            if (logger.isDebugEnabled()) {
                logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
                        + "' and '" + definition.getBeanClassName() + "' mapperInterface");
            }

            // the mapper interface is the original class of the bean
            // but, the actual class of the bean is MapperFactoryBean
            definition.getConstructorArgumentValues ().addGenericArgumentValue( definition.getBeanClassName ()); // issue # 59 add construction method
            definition.setBeanClass(this.mapperFactoryBean.getClass());
            //Set up general mapper
            if(StringUtils.hasText(this.mapperHelperBeanName)){
                definition.getPropertyValues().add("mapperHelper", new RuntimeBeanReference(this.mapperHelperBeanName));
            } else {
                //The default mode is used when no configuration is made
                if(this.mapperHelper == null){
                    this.mapperHelper = new MapperHelper();
                }
                definition.getPropertyValues().add("mapperHelper", this.mapperHelper);
            }

            definition.getPropertyValues().add("addToConfig", this.addToConfig);

            boolean explicitFactoryUsed = false;
            if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
                definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
                explicitFactoryUsed = true;
            } else if (this.sqlSessionFactory != null) {
                definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
                explicitFactoryUsed = true;
            }

            if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
                if (explicitFactoryUsed) {
                    logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
                }
                definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
                explicitFactoryUsed = true;
            } else if (this.sqlSessionTemplate != null) {
                if (explicitFactoryUsed) {
                    logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
                }
                definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
                explicitFactoryUsed = true;
            }

            if (!explicitFactoryUsed) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
                }
                definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
            }
        }
    }

Recommended Today

Review of SQL Sever basic command

catalogue preface Installation of virtual machine Commands and operations Basic command syntax Case sensitive SQL keyword and function name Column and Index Names alias Too long to see? Space Database connection Connection of SSMS Connection of command line Database operation establish delete constraint integrity constraint Common constraints NOT NULL UNIQUE PRIMARY KEY FOREIGN KEY DEFAULT […]