Spring component registration - springboot actual e-commerce project mall4j

Posted by UQKdk on Mon, 13 Dec 2021 05:26:39 +0100

springboot e-commerce project mall4j( https://gitee.com/gz-yami/mall4j)

java mall system source code

1. bean registration

We have a Person class

public class Person {

    private Integer age;
    
    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

1.1 traditional bean registration

New beans 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.xsd">
    
    <bean id="person" class="com.opgame.spring.Person">
        <property name="age" value="18"/>
        <property name="name" value="Zhang San"/>
    </bean>

</beans>

Use the person object to test

@Test
public void testBean() {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Person person = (Person)context.getBean("person");
    System.out.println(person);
}

1.2 using annotation instead of xml registration

Create a java class with @ Configuration and register with @ Bean

@Configuration // Tell spring that this is a config class
public class BeansConfig {

    // Register a bean for the container. The type is the return value type. The default id is the method name. Set the id in the bean annotation
    @Bean("person")
    public Person person() {
        Person person = new Person();
        person.setAge(20);
        person.setName("Li Si");
        return person;
    }
}

Use the person object to test

@Test
public void testBean() {
    ApplicationContext context = new AnnotationConfigApplicationContext(BeansConfig.class);
    Person person = (Person)context.getBean("person");
    System.out.println(person);
}

2 exclude,include filter

In traditional spring mvc projects, in order to make transactions effective, we usually use context XML for the exclude @Controller class in MVC XML includes @ controller. When we use some third-party class libraries, we sometimes need to scan the exclusion code of some classes. What should we do?

2.1 traditional xml exclusion and import scan classes

context.xml (requires context namespace)

<context:component-scan base-package="com.opgame">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

mvx.xml

<!-- use-default-filters default tureļ¼ŒDefault scan@Component @Repository @Service @Controller -->
    <context:component-scan base-package="com.opgame" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

2.2 exclude and import scan classes in the form of annotations

@ComponentScan annotation usage

  • value: Specifies the package to scan
  • excludeFilters = Filter []: Specifies the rules to exclude those components during scanning
  • includeFilters = Filter []: specifies which components only need to be included during scanning
  • useDefaultFilters: whether to use the default Filters

Filter

  • FilterType.ANNOTATION: according to the annotation
  • FilterType.ASSIGNABLE_TYPE: according to the given type
  • FilterType.ASPECTJ: use ASPECTJ expressions
  • FilterType.REGEX: specify with regular
  • FilterType.CUSTOM: use custom rules
  • classes: ANNOTATION,ASSIGNABLE_ Class given by type and CUSTOM
  • pattern: the expression given by ASPECTJ and REGEX
@Configuration // Tell spring that this is a config class
@ComponentScan(value="com.opgame",useDefaultFilters=false,
includeFilters= {
        @Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
},
excludeFilters= {
        @Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {PersonController.class})
})
public class BeansConfig{
    
} 

Custom rules

// Implementation org springframework. core. type. filter. Typefilter interface
public class BeanTypeFilter implements TypeFilter{

    /**
     * @param metadataReader Get the metadata of the current class scanned by spring
     * @param metadataReaderFactory The factory for obtaining metadata is used to obtain the information of other classes
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // Get the meta information of the current class annotation
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // Gets the class information of the current class
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // Gets the resource (classpath) of the current class
        Resource resource = metadataReader.getResource();
        
        // If the current class name contains person, the configuration is successful
        if(classMetadata.getClassName().contains("person")) {
            return true;
        }
        return false;
    }
}

3. Scope and lazy loading

3.1 xml

<!-- default scope="singleton" Single case-->
<!-- lazy-init="true" Objects are created only when needed. The default value is spring Created on initialization-->
<bean id="person" class="com.opgame.spring.Person" scope="singleton" lazy-init="true">
        <property name="age" value="18"/>
        <property name="name" value="Zhang San"/>
</bean>

3.2 notes

@Lazy
@Scope("singleton")
@Bean("person")
public Person person() {
    Person person = new Person();
    person.setAge(20);
    person.setName("Li Si");
    return person;
}

4. Register according to conditions

Sometimes, when we write a framework or code, we need to switch to different implementation methods in different environments. So when to load the implementation of that class, spring provides us with this annotation

Use the @ Conditional annotation in spring to load classes on demand.

@Conditional({
    LinuxCondition.class
})
public Person person1() {
    Person person = new Person();
    person.setAge(18);
    person.setName("Li Xiaosi");
    return person;
}
// Implementation org springframework. context. annotation. Condition interface
public class LinuxCondition  implements Condition{
    
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // Get beanfactory used by ioc
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // Get class loader
        ClassLoader classLoader = context.getClassLoader();
        // Get current environment
        Environment environment = context.getEnvironment();
        // Get bean registration class
        BeanDefinitionRegistry registry = context.getRegistry();
        
        // Determine whether the person object is included
        boolean hasPerson = registry.containsBeanDefinition("person");
        if (!hasPerson) {
            return false;
        }
        
        // Determine whether it belongs to linux Environment
        if(environment.getProperty("os.name").contains("linux")) {
            return true;
        }
        return false;
    }
}

You can also view Environment related notes by setting vm arguments when starting the program

-Dos.name=linux

You can also

In spring boot, @ ConditionalOnMissingBean(name="xxx") @ConditionalOnMissingBean(xxx.class) can also be used to determine whether to register when there are no classes or methods.

5. Use import to register

Multiple existing classes

class Blue {}

class Color {}

class Red {}

5.1 simple registration

When we need to register without parameters, we can use @ import to register, such as:

@Configuration
@Import({Blue.class,Red.class})
public class BeansConfig {
    
}

Where bean id is the full name of the class, such as com opgame. spring. bean. Blue com. opgame. spring. bean. Red

amount to

@Configuration
public class BeansConfig {
    @Bean("com.opgame.spring.bean.Blue")
    public Blue blue() {
        return new Blue();
    }
    
    @Bean("com.opgame.spring.bean.Red")
    public Red red() {
        return new Red();
    }
}

5.2 class name registration using ImportSelector

// Custom logic returns the components to be imported
// Implementation org springframework. context. annotation. Importselector interface
public class BeanImportSelector implements ImportSelector{

    /**
     * importingClassMetadata: You can obtain all annotation meta information of the currently annotated @ Import annotation
     *     Beansconfig. In the current example Meta information of all annotations of class
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // null return is not allowed
        return new String[] {"com.opgame.spring.bean.Blue","com.opgame.spring.bean.Red"};
    }
}
@Configuration
@Import({BeanImportSelector.class})
public class BeansConfig {
    
}

5.3 ImportBeanDefinitionRegistrar registers a bean into the container

At this time, the bean definition is registered, that is, the bean definition information, and spring will register the bean according to the bean definition information! That is, there is no bean registered at this time!!!

// Implementation org springframework. context. annotation. Importbeandefinitionregistrar interface
public class BeansImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{

    /**
     * importingClassMetadata: Annotation information of the current config class (beansConfig)
     * registry: Bean Register the class. You can call beandefinitionregistry here for all beans that need to be added to the container Register with the registerbeandefinition() method
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean hasBlue = registry.containsBeanDefinition("com.opgame.spring.bean.Blue");
        boolean hasRed = registry.containsBeanDefinition("com.opgame.spring.bean.Red");
        // If there are red and blue, a Color object with id Color is registered
        if (hasBlue && hasRed) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Color.class);
            registry.registerBeanDefinition("color", beanDefinition);
        }
    }

}
@Configuration
@Import({Blue.class,Red.class,BeansImportBeanDefinitionRegistrar.class})
public class BeansConfig {
    
}

6. Implement factorybean <? > Interface registration bean

// Implementation org springframework. beans. factory. Factorybean interface
public class PersonFactoryBean implements FactoryBean<Person>{

    // Construct person object
    public Person getObject() throws Exception {
        return new Person();
    }

    // Gets the type of the current object
    public Class<?> getObjectType() {
        return Person.class;
    }

    // Is it a single instance
    public boolean isSingleton() {
        return true;
    }
}
@Configuration
public class BeansConfig {
    @Bean
    public PersonFactoryBean personFactoryBean() {
        return new PersonFactoryBean();
    }
}

Use the person object to test

@Test
public void testBean() {
    ApplicationContext context = new AnnotationConfigApplicationContext(BeansConfig.class);
    context.getBean("personFactoryBean").getClass(); // com.opgame.spring.Person
    
    // The & symbol is required to get the bean object constructed by the factory
    Person person = (Person)context.getBean("&personFactoryBean"); 
    
    // If & is not used, the factory itself is obtained
    PersonFactoryBean personFactoryBean = (PersonFactoryBean)context.getBean("personFactoryBean"); 
    
    System.out.println(person);
}

7 created by BeanDefinitionBuilder

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
builder.addPropertyValue("id", 1);
builder.addPropertyValue("name", "Li Si");
registry.registerBeanDefinition("user", builder.getBeanDefinition());

springboot e-commerce project mall4j( https://gitee.com/gz-yami/mall4j)

java mall system source code

Topics: Spring Spring Boot