Spring annotation development


Introduction to annotation development

Benefits of annotation development: use the form of annotation instead of xml configuration, completely eliminate the complex Spring configuration file from the project and simplify writing.

Disadvantages of annotation driven:

  • In order to achieve annotation driven purposes, the original simple writing may be made more complex.

  • It is very convenient to configure third-party development resources in XML, but annotation driven can not be edited in third-party development resources, so it will increase the development workload.


Common notes

Spring original annotation: it mainly replaces the configuration of < bean >.

annotation explain
@Component Used on classes to instantiate beans
@Controller Use to instantiate beans on web tier classes
@Service Used on the service layer class to instantiate beans
@Repository Used on dao layer classes to instantiate beans
@Autowired Use on field for type dependent injection
@Qualifier Used in conjunction with @ Autowired for dependency injection by name and reference type
@Resource Equivalent to @ Autowired + @Qualifier, inject reference types by name
@Value Inject properties of common types
@Scope Label the scope of the Bean
@PostConstruct Use to label the method, which is the initialization method of the Bean
@PreDestroy Use to mark the method as the Bean's destruction method

Spring new annotation:

The above annotations cannot completely replace the xml configuration file. The configurations that need to be replaced by annotations are as follows:

  • Configuration of non custom beans: < Bean >
  • Load the configuration of the properties file: < context: Property placeholder >
  • Configuration of component scan: < context: component scan >
  • Import other files: < import >
annotation explain
@Configuration It is used to specify that the current class is a Spring configuration class, and annotations will be loaded from this class when creating a container. Used to specify the packages that Spring will scan when initializing the container.
@ComponentScan The function is the same as < context: component scan base package = "com. Itheima" / > in the xml configuration file of Spring.
@Bean On a method, annotations store the return value of the method in the Spring container.
@PropertySource Used to load the configuration in the. properties file.
@Import Used to import other configuration classes.

Enable annotation

  • Start annotation scanning and load the annotation items configured in the class:
<context:component-scan base-package="packageName"/>
  • explain:

    • When the package is scanned, all files in the configured package and its sub packages are scanned.

    • The scanning process is carried out in the form of folder recursive iteration.

    • The scan process reads only valid java files.

    • Only spring recognized annotations are read during scanning.

    • After the scan, the recognizable valid annotations will be converted into resources corresponding to spring and added to the IoC container.

  • be careful:

    • Whether in annotation format or XML configuration format, resources are ultimately loaded into the IoC container. The only difference is that the data is read in different ways.

    • In terms of loading efficiency, annotations are better than XML configuration files.


bean definitions: @ Component, @ Controller, @ Service, @ Repository

  • Type: class annotation

  • Location: above the class definition.

  • Function: set this class as a spring managed bean.

  • Example:

@Component
public class ClassName{}
  • Note: @ Controller, @ Service, @ Repository are derived annotations of @ Component, and their functions are the same as those of @ Component.

  • Related properties:

    • Value (default): defines the access id of the bean.

bean reference type attribute injection: @ Autowired, @ Qualifier

  • Type: attribute annotation, method annotation

  • Location: above the attribute definition and above the method definition.

  • Function: set the object of the corresponding property or reference the method, and transfer the type parameter.

  • Note: @ Autowired is assembled by type by default. After specifying @ Qualifier, you can specify the id of the assembled bean.

  • Related properties:

    • required: defines whether the property is allowed to be null.

bean reference type attribute injection: @ Inject, @ Named, @ Resource

  • explain:

    • @Inject and @ Named are annotations in the JSR330 specification. Their functions are exactly the same as @ Autowired and @ Qualifier, and are applicable to different architecture scenarios.
    • @Resource is an annotation in JSR250 specification, which can simplify the writing format.
  • @Resource related properties:

    • name: set the id of the injected bean.

    • Type: sets the type of the injected bean, and the received parameter is Class type.


bean reference type attribute injection: @ Primary

  • Type: class annotation

  • Location: above the class definition.

  • Function: set the bean corresponding to the class to be assembled first when assembled by type.

  • Note: @ Autowired is assembled by type by default. When bean s of the same type appear, using @ Primary will increase the priority of automatic assembly by type, but multiple @ Primary will lead to invalid priority settings.


Non reference type property injection of bean: @ Value

  • Type: attribute annotation, method annotation

  • Location: above the attribute definition and above the method definition.

  • Function: set the value of the corresponding attribute or transfer parameters to the method.

  • explain:

    • The value value only supports non reference type data. When assigning values, all parameters of the method are assigned values.

    • The value value supports reading the property value in the properties file and passing the data in the properties into the class through the class property.

    • Value value supports spiel.

    • @If the value annotation is added above the attribute, the set method can be omitted (the purpose of the set method is to assign a value to the attribute).


Scope of bean: @ scope

  • Type: class annotation

  • Location: above the class definition.

  • Function: set this class as the scope attribute corresponding to the bean.

  • Related properties

    • Value (default): defines the scope of the bean. The default is singleton.

bean life cycle: @ PostConstruct, @ PreDestroy

  • Type: Method annotation

  • Location: above the method definition.

  • Function: set this class as the corresponding lifecycle method of the bean.


Load third-party resources: @ Bean

  • Type: Method annotation

  • Location: above the method definition.

  • Function: set the return value of this method as a spring managed bean.

  • example:

@Bean("dataSource")
public DruidDataSource createDataSource() {    return ......;    }
  • explain:

    • Because third-party beans cannot be modified on their source code, you can use @ Bean to solve the problem of introducing third-party beans.

    • This annotation is used to create bean s instead of static factories and instance factories in XML configuration, and does not distinguish whether the method is static or non static.

    • @The class where the Bean is located must be scanned and loaded by spring, otherwise the annotation cannot take effect.

  • Related properties

    • Value (default): defines the access id of the bean.

Load properties file: @ PropertySource

  • Type: class annotation

  • Location: above the class definition.

  • Function: load the property value in the properties file.

  • example:

@PropertySource(value="classpath:jdbc.properties")
public class ClassName {
    @Value("${propertiesAttributeName}")
    private String attributeName;
}
  • Note: the * wildcard format is not supported. Once loaded, the corresponding attribute values can be used in all spring controlled bean s

  • Related properties

    • Value (default): sets the name of the loaded properties file.

    • ignoreResourceNotFound: whether to ignore if the resource is not found. The default value is false.


Pure annotation development: @ Configuration, @ ComponentScan

  • Type: class annotation

  • Location: above the class definition.

  • Function: set the current class to load the spring core configuration class (spring configuration file is no longer required).

  • example:

@Configuration
@ComponentScan("scanPackageName")
public class SpringConfigClassName{
}

- explain:

  - Core mating classes are used to replace spring Core configuration file. This class can be set to be empty without setting variables and properties.

  - bean Notes for scanning work @ComponentScan replace.

- To load a pure annotation format context object, you need to use AnnotationConfigApplicationContext: 

```java
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Import third-party configuration: @ import

  • Type: class annotation

  • Location: above the class definition.

  • Function: import third-party bean s as spring controlled resources.

  • example:

@Configuration
@Import(OtherClassName.class)
public class ClassName {
}
  • explain:

    • @The Import annotation can only be added once on the same class. If you need to Import more than one, you can set it in the form of array.

    • In the imported class, you can continue to use @ Import to Import other resources (see).

    • @The class of the bean can be imported into the spring container without declaring it as a bean.


Comprehensive case

maven dependency:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>

spring configuration class

DataSourceConfig.java:

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

// Data source configuration class
// Equivalent to < context: Property placeholder location = "classpath: JDBC. Properties" / >, and wildcards cannot be used*
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {

    @Value("${jdbc.driver}")
    private static String driver;
    @Value("${jdbc.url}")
    private static String url;
    @Value("${jdbc.username}")
    private static String username;
    @Value("${jdbc.password}")
    private static String password;

    @Bean("dataSource")  // Place the return value of the method in the Spring container
    public static DruidDataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

SpringConfig.java:

package com.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

// Spring core configuration class
@Configuration
@ComponentScan("com")  // Equivalent to < context: component scan base package = "com" / >
@Import({DataSourceConfig.class})  // Equivalent to < import resource = "" / >
public class SpringConfig {

}

dao layer

UserDaoImpl.java:

package com.dao.impl;

import com.dao.UserDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

// Equivalent to < bean id = "userdao" ref = "com. Dao. Impl. Userdaoimpl" / >
// @Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("UserDao save...");
    }
}

service layer

UserServiceImpl.java:

package com.service.impl;

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.sql.DataSource;

// Equivalent to < bean id = "userservice" ref = "com. Service. Impl. Userserviceimpl" / >
// @Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {

    // <property name="userDao" ref="userDao"></property>
    // @Autowired / / can be used separately and matched from the spring container according to the data type (there will be a matching problem when there are multiple bean s with the same data type)
    // @Qualifier("userDao") / / the id of the specified bean is matched from the spring container and used in combination with @ Autowired
    @Resource(name="userDao")  // Equivalent to @ Autowired+@Autowired
    UserDao userDao;

    @Resource(name="dataSource")
    DataSource dataSource;

    @Value("${jdbc.driver}")  // Read the value in the configuration file
    private String driver;

    /* The set method can be omitted when using annotation development, but cannot be omitted when using configuration file
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    */

    @Override
    public void save() {
        System.out.println("driver: "+driver);
        System.out.println("dataSource: "+dataSource);
        userDao.save();
    }

    @PostConstruct
    public void init() {
        System.out.println("service Object initialization method");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("service Object destruction method");
    }
}

controller layer

App.java:

package com.controller;

import com.config.SpringConfig;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {

    public static void main(String[] args) {
        // ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = (UserService)context.getBean("userService");
        userService.save();
        context.close();
    }
}

Operation results:

service Object initialization method
dataSource: {
    CreateTime:"2021-12-03 01:05:00",
    ActiveCount:0,
    PoolingCount:0,
    CreateCount:0,
    DestroyCount:0,
    CloseCount:0,
    ConnectCount:0,
    Connections:[
    ]
}
UserDao save...
service Object destruction method

Integrate third-party technology

Annotation integration Mybatis

Note the development steps of integrating MyBatis:

  1. Modify the format of mybatis external configuration file to annotation format;
  2. The business class uses @ Component to declare bean s and @ Autowired to inject objects;
  3. Create configuration files JDBCConfig and MyBatisConfig classes and import them into the core configuration class SpringConfig;
  4. Enable annotation scanning;
  5. Use the AnnotationConfigApplicationContext object to load configuration items.

Project address

The core contents are as follows:

  • Maven dependency:
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
  • MybatisConfig.java (Mybatis configuration class):
package com.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class MybatisConfig {

    /*
    <!-- spring After integrating mybatis, create objects for connection -- >
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.domain"/>
    </bean>

    <!-- Scan the mybatis mapping configuration and manage it as a spring bean -- >
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dao"/>
    </bean>
     */

    // The following annotation replaces the content of the above configuration file: the return value will be used as the bean of the Spring container
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.domain");
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.dao");
        return mapperScannerConfigurer;
    }

}
  • SpringConfig.java (Spring core configuration class):
package com.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan("com")  // Equivalent to < context: component scan base package = "com" / >
@Import({DataSourceConfig.class, MybatisConfig.class})  // Equivalent to < import resource = "" / >
public class SpringConfig {

}

Annotation integration Junit

Annotation integration Junit development steps:

  1. Spring takes over the running rights of Junit and uses the Junit class loader dedicated to spring;

2. Set the corresponding Spring container for Junit test cases:

  • After Spring 5.0, Junit version must be 4.12 or above.

  • Junit is only used for unit testing. Junit's test class cannot be configured as a Spring bean, otherwise the configuration will be packaged into the project.

Example: integrating Junit5

  • Maven dependency:
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
  • Test class:
package com.service;

import com.config.SpringConfig;
import com.domain.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.List;

// Set the spring specific class loader
@ExtendWith(SpringExtension.class)
// Set the configuration corresponding to the loaded spring context
@ContextConfiguration(classes=SpringConfig.class)
public class UserServiceTest {

    @Autowired
    UserService userService;

    @Test
    public void testFindById() {
        User user = userService.findById(1);
        // System.out.println(user);
        Assertions.assertEquals("Mick", user.getName());
    }

    @Test
    public void testFindAll() {
        List<User> users = userService.findAll();
        Assertions.assertEquals(3, users.size());
    }

}

IoC underlying core principles

IoC core interface


Component scanner: @ ComponentScan

Component scanner: during the development process, you need to load the necessary beans or exclude the specified beans according to the requirements.

Application scenario:

  • Data layer interface test
  • Business layer interface test
  • Various operating environment settings

Configure scanner

  • Name: @ ComponentScan

  • Type: class annotation

  • Location: above class definition

  • Function: set spring configuration loading class scanning rules

  • example:

@Configuration
@ComponentScan(
    value="com",  // Set basic scan path
    excludeFilters =      // Set filtering rules. Currently, it is exclude filtering
    @ComponentScan.Filter(            // catalog filter
        type= FilterType.ANNOTATION,  // Set the filtering method to filter by annotation
        classes=Repository.class)     // Set specific filter items. If all @ Repository decorated bean s are not loaded
)
public class SpringConfig {

}
  • includeFilters: sets inclusive filters

  • excludeFilters: sets exclusive filters

  • Type: sets the filter type (filter Policy)

    • ANNOTATION
    • ASSIGNABLE_TYPE
    • ASPECTJ
    • REGEX
    • CUSTOM

Custom scanner

  • Name: TypeFilter

  • Type: Interface

  • Role: custom type filter

Example:

  • Custom scanner
public class MyTypeFilter implements TypeFilter {
    public boolean match(MetadataReader mr, MetadataReaderFactory mrf) throws IOException {
        ClassMetadata cm = metadataReader.getClassMetadata();
        tring className = cm.getClassName();
        if(className.equals("com.itheima.dao.impl.BookDaoImpl")){
            return true;  // Filter (intercept)
        }
        return false;  // No filtering (release)
    }
}
  • Configuration class:
@Configuration
@ComponentScan(
        value = "com",
        excludeFilters = @ComponentScan.Filter(
                type= FilterType.CUSTOM,
                classes = MyTypeFilter.class
        )
)
public class SpringConfig {

}

Custom importer: ImportSelector

Only through configuration can bean s enter the spring container, be loaded and controlled by spring. Beans are configured as follows:

  • Use < bean / > tag configuration in XML file

  • Use @ Component and derived annotation configuration

In the process of enterprise development, you usually need to configure a large number of beans, so you need a way to configure a large number of beans quickly and efficiently.

ImportSelector annotation:

  • Type: Interface

  • Function: Custom bean importer (import beans without @ Component annotation)

Example:

  • Custom importer:
public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata icm) {
        // Returns the array of beans to be imported. The bean can be scanned and recognized even without @ Component annotation
        return new String[]{"com.dao.impl.AccountDaoImpl"};
    }
}
  • Configuration class:
@Configuration
@ComponentScan("com")
@Import(MyImportSelector.class)  // Import custom importer
public class SpringConfig {
}

Encapsulation tool class of custom importer:

import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class CustomerImportSelector implements ImportSelector {

    private String expression;

    public CustomerImportSelector(){
        try {
            //Specify the name of the loaded properties file during initialization
            Properties loadAllProperties = PropertiesLoaderUtils.loadAllProperties("import.properties");
            //Sets the name of the loaded property
            expression = loadAllProperties.getProperty("path");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //1. Define the name of the scan package
        String[] basePackages = null;
        //2. Judge whether there is @ ComponentScan annotation on the class with @ Import annotation
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            //3. Take out the attribute of @ ComponentScan annotation
            Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
            //4. Get the value of the basePackages attribute with the attribute name
            basePackages = (String[]) annotationAttributes.get("basePackages");
        }
        //5. Judge whether there is this attribute (if there is no ComponentScan annotation, the attribute value is null; if there is ComponentScan annotation, basePackages defaults to an empty array)
        if (basePackages == null || basePackages.length == 0) {
            String basePackage = null;
            try {
                //6. Fetch the package name containing the @ Import annotation class
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //7. Store in array
            basePackages = new String[] {basePackage};
        }
        //8. Create a classpath scanner
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        //9. Create a type filter (pointcut expression type filter is used here)
        TypeFilter typeFilter = new AspectJTypeFilter(expression,this.getClass().getClassLoader());
        //10. Add a type filter to the scanner
        scanner.addIncludeFilter(typeFilter);
        //11. Create a collection of fully qualified class names
        Set<String> classes = new HashSet<>();
        //12. Populate set data
        for (String basePackage : basePackages) {
            scanner.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
        }
        //13. Return according to the rules
        return classes.toArray(new String[classes.size()]);
    }
}

Custom registrar: ImportBeanDefinitionRegistrar

  • Type: Interface

  • Role: Customize bean definition register (identify beans marked with @ Component)

Example:

  • Custom registrar:
// Indicates that all bean s under the com directory are registered
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata icm, BeanDefinitionRegistry r) {
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(r, false);
        TypeFilter tf = new TypeFilter() {
            public boolean match(MetadataReader mr, MetadataReaderFactory mrf) throws IOException {
                return true;
            }
        };
        scanner.addIncludeFilter(tf);  // contain
        // scanner.addExcludeFilter(tf);  //  exclude
        scanner.scan("com");
    }
}
  • Configuration class:
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)  // Equivalent to @ ComponentScan("com")
public class SpringConfig {
}

Encapsulation tool class:

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

public class CustomeImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private String expression;

    public CustomeImportBeanDefinitionRegistrar(){
        try {
            //Specify the name of the loaded properties file during initialization
            Properties loadAllProperties = PropertiesLoaderUtils.loadAllProperties("import.properties");
            //Sets the name of the loaded property
            expression = loadAllProperties.getProperty("path");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //1. Define the name of the scan package
        String[] basePackages = null;
        //2. Judge whether there is @ ComponentScan annotation on the class with @ Import annotation
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            //3. Take out the attribute of @ ComponentScan annotation
            Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
            //4. Get the value of the basePackages attribute with the attribute name
            basePackages = (String[]) annotationAttributes.get("basePackages");
        }
        //5. Judge whether there is this attribute (if there is no ComponentScan annotation, the attribute value is null; if there is ComponentScan annotation, basePackages defaults to an empty array)
        if (basePackages == null || basePackages.length == 0) {
            String basePackage = null;
            try {
                //6. Fetch the package name containing the @ Import annotation class
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //7. Store in array
            basePackages = new String[] {basePackage};
        }
        //8. Create a classpath scanner
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false);
        //9. Create a type filter (pointcut expression type filter is used here)
        TypeFilter typeFilter = new AspectJTypeFilter(expression,this.getClass().getClassLoader());
        //10. Add a type filter to the scanner
        scanner.addIncludeFilter(typeFilter);
        //11. Scan the specified package
        scanner.scan(basePackages);
    }
}

bean initialization process parsing

bean unified initialization

  • BeanFactoryPostProcessor

    • Function: defines the actions to be executed after the bean factory object is created and before the bean object is created. It is used for post creation business processing of the factory.

    • Running time: the current operation is used to process the plant and only runs once.

  • BeanPostProcessor

    • Function: defines the unified actions before and after initialization of all beans, which are used for pre creation business processing and post creation business processing of beans.

    • Run time: the current operation is accompanied by the creation process of each bean. This operation is run every time a bean is created.

  • InitializingBean

    • Function: defines the action before initialization of each bean, which belongs to non-uniform action and is used for business processing before bean creation.

    • Running time: the current operation is accompanied by the creation process of any bean to ensure its personalized business processing.

  • Note: the above operations need to be loaded by the spring container before they can run.

Example:

  • BeanFactoryPostProcessor:
package com.post;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactory implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("Bean The factory made it");
    }
}
  • BeanPostProcessor:
package com.post;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBean implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean Before balabalabala");
        System.out.println(beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean Then balabalabala");
        return bean;
    }
}
  • InitializingBean:
package com.service.impl;

import com.dao.UserDao;
import com.domain.User;
import com.service.UserService;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service("userService")
public class UserServiceImpl implements InitializingBean {

    // Defines the initialization operation of the current bean, which is equivalent to the init method attribute configuration
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("UserServiceImpl......bean ...init......");
    }
}
  • Operation results:
Bean The factory made it
bean Before balabalabala
springConfig
bean Then balabalabala
bean Before balabalabala
com.config.DataSourceConfig
bean Then balabalabala
bean Before balabalabala
dataSource
bean Then balabalabala
bean Before balabalabala
getSqlSessionFactoryBean
bean Then balabalabala
bean Then balabalabala
bean Before balabalabala
userDao
bean Then balabalabala
bean Then balabalabala
bean Before balabalabala
userService
UserServiceImpl......bean ...init......
bean Then balabalabala
bean Before balabalabala
com.service.UserServiceTest.ORIGINAL
bean Then balabalabala

Single bean initialization

  • FactoryBean: encapsulates the initialization process of a single bean to simplify configuration.

Difference between FactoryBean and BeanFactory:

  • FactoryBean: encapsulates the creation process of a single bean. This is usually preparation for creating another bean.

  • BeanFactory: the top-level interface of Spring container, which uniformly defines bean related acquisition operations.

Example:

import org.springframework.beans.factory.FactoryBean;

public class UserServiceImplFactoryBean implements FactoryBean {

    // Key: return data
    @Override
    public Object getObject() throws Exception {
        return new UserServiceImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

Posted on Fri, 03 Dec 2021 14:01:54 -0500 by csj16