Common underlying core annotations for Spring source code analysis

Keywords: Spring source code

1, Introduction to the overall functions of Spring framework

        

1,Spring Core Container:

         Module function: Core and Beans modules are the basic parts of the framework, providing IoC (transition control) and dependency injection features. The basic concept here is BeanFactory, which provides a classic implementation of Factory pattern to eliminate the need for procedural singleton pattern, and really allows you to separate dependencies and configurations from program logic

1.1) Core

         It mainly contains the basic Core tool classes of the Spring framework. Other Spring components use the classes in this package. The Core module is the basic Core of other components.

1.2) beans (the role of beanfactory)

         It contains all classes related to accessing configuration files, creating and managing bean s, and performing inversion of control I dependency injection (IOC / DI) operations  .

1.3) context (processing BeanFactory, or the role of ApplicationContext)

         Modeling is based on Core and Beans modules, and provides a framework object access method similar to JNDI registrar. The Context module inherits the characteristics of Beans, provides a large number of extensions for the Spring Core, and adds support for internationalization (such as resource binding), event propagation, resource loading and transparent creation of Context. The Context module also supports some J2EE features. The ApplicationContext interface is the key to the Context module.

         Essential difference: (beans using beanfactory are loaded with delay, while ApplicationContext is loaded without delay)

1.4)Expression Language

         The module provides a powerful expression language for querying and manipulating objects at run time. It is an extension of the unifed expression language defined in the JSP 2.1 specification. The language supports setting / obtaining the value of attributes, attribute allocation, method call, accessing the context of arrays, containers and indexers, logical and arithmetic operators, named variables, and retrieving objects by name from the IoC container of Spring. It also supports list projection, selection, and general list aggregation.

2: Spring Data Access/Integration

        2.1)JDBC

         Provides a JDBC abstraction layer, which can eliminate lengthy JDBC coding and parse database factory specific error codes. This module contains all classes encapsulated by Spring for JDBC data access,

         2.2)ORM module is a popular relational mapping API

         For example, JPA, JDO, Hibernate, iBatis, etc. provide an interaction layer. Using the ORM package, you can mix all the features provided by Spring for O/R mapping, such as the simple declaration transaction management mentioned earlier.

         2.3) the oxm module provides an abstraction layer for the implementation of ObjectXML mapping

         Object/XML mappings include JAXB, Castor, XMLBeans, JiBX, and XStream

        2.4)JMS(Java Messageing Service)

        The module mainly contains some features of manufacturing and consumption messages.

        2.2)Transaction

         Support programmatic and declarative transaction management. These transaction classes must implement specific interfaces and apply to all POJO s.

3: Spring Web

     Web module: it provides basic web oriented integration features c, such as multi file upload, initializing IoC container with servlet listeners, and a web oriented application context. It also includes web related parts of Spring remote support.     

4: Spring Aop

         4.1) the aspects module provides integration support for AspectJ.

         4.2) the instrumentation module provides class instrumentation support and classloader implementation, so that it can be used on a specific application server      

5: Test

         The Test module supports testing Spring components using JUnit and TestNG

  6:Spring container inheritance diagram:

 

7: Control inversion and dependency injection  

         7.1) what is control reversal? I think it is necessary to understand an important idea of software design: Dependency Inversion Principle

         ① : what is the dependency inversion principle? Suppose we design a car: first design the wheels, then design the chassis according to the size of the wheels, then design the body according to the chassis, and finally design the whole car according to the body. There is a "dependency" relationship here: the car depends on the body, the body depends on the chassis, and the chassis depends on the wheels.

        

 

         What's wrong with the picture above? However, if the tire size is changed, the site needs to be changed, the site needs to be changed, and the body needs to be changed, so that the whole car structure has been changed. Then the car company went bankrupt

         The chairman relies on the general manager to win, the general manager relies on the Department Manager to earn money, and the Department Manager relies on the employees to win. What should we do if the employees leave?

         Conversely, if the automobile company decides to modify the tire, we only need to change the design of the wheel without moving the chassis, body and automobile design.

        

         The core of ioc's idea is that resources are not managed by both parties who use resources, but by a third party who does not use resources, which can bring many benefits. First, centralized resource management to realize the configurable and easy management of resources. Second, it reduces the dependence of both parties using resources, that is, the degree of coupling.

2: Spring IOC container bottom annotation usage  

         2.1) form of XML configuration file VS form of configuration class

         ① : define Bean information based on 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="car" class="com.tuling.testconfiuration.compent.Car"></bean>

    <bean id="driverFactoryBean" class="com.tuling.testfactorybean.DriverFactoryBean">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tuling-multids00"></property>
    </bean>
</beans>

         Read Bean from container

public class MainClass {

    public static void main(String[] args) {
        //XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("XmlBean.xml"));
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("XmlBean.xml");

        System.out.println(ctx.getBean("person"));
    }
}

         ② : define Bean information based on the form of read configuration class

@Configuration
public class MainConfig {

    @Bean
    public Person person(){
        return new Person();
    }
}

        Note: if it is applicable in the form of @ bean, the default name of the bean is the method name. If @ Bean(value="bean name"), the bean name is specified

         Read the Bean information from the container (pass in the configuration class)

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println(ctx.getBean("person"));
    }
}

         2.2) write @ CompentScan annotation on the configuration class to scan the package

@Configuration 
@ComponentScan(basePackages = {"com.tuling.testcompentscan"}) 
public class MainConfig {
 }

         ① : exclusion usage excludefilters (excluding @ Controller annotation and turingservice)

@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
})
public class MainConfig {
}

         ② : includeFilters. Note that if you use the included usage, you need to set the useDefaultFilters property to false (true means to scan all)

@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},excludeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,value = TulingFilterType.class)
},includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Repository.class)
})
public class MainConfig {
}

         ③ Type of @ ComponentScan.Filter type

  •          Filtertype.annotation in annotation form @ controller @ service @ repository @ complex
  • Filtertype.assignable of the specified type_ TYPE @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
  • Filtertype.aspectj of AspectJ type (not commonly used)
  • Filtertype.regex for regular expressions (not commonly used)
  • )Custom FilterType.CUSTOM
package org.springframework.context.annotation;

public enum FilterType {
    ANNOTATION,
    ASSIGNABLE_TYPE,
    ASPECTJ,
    REGEX,
    CUSTOM;

    private FilterType() {
    }
}

         ③ ① how to use FilterType.CUSTOM custom type

        

public class TulingFilterType implements TypeFilter {

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //Gets the annotation source information of the current class
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

        //Gets the source information of the class of the current class
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //Gets the resource information of the current class
        Resource resource =  metadataReader.getResource();
        System.out.println("Path to class:"+classMetadata.getClassName());
        if(classMetadata.getClassName().contains("dao")) {
            return true;
        }
        return false;
    }
}

@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,value = TulingFilterType.class)
},useDefaultFilters = false)
public class MainConfig {
}

2.3) configure the scope object of the Bean

         ① : when @ Scope is not specified, all beans are single instance beans, and are loaded (the container starts and the instance is created)

@Configuration
public class MainConfig {

    /**
     * The configured bean is single instance by default
     * @return
     */
    @Bean
    public Person person() {
        return new Person();
    }
}

② : specify @ Scope as prototype, which means it is multi instance, and it is loaded in lazy mode (the object will not be created when the IOC container is started, but will be created when it is used for the first time)

@Configuration
public class MainConfig {

    /**
     * The configured bean is single instance by default
     * @return
     */
    @Bean
    @Scope(scopeName = "prototype")
    public Person person() {
        return new Person();
    }
}

         ③ : @ Scope specified Scope method value

  • singleton single instance (default)
  • prototype multi instance
  • Request same request
  • Session the same session level

2.4) lazy loading @ lazy of bean (mainly for single instance bean containers. Objects are not created when they are started, but only when they are used for the first time)

@Configuration
public class MainConfig {

    /**
     * The configured bean is single instance by default
     * @return
     */
    @Bean
    @Lazy
    //@Scope(scopeName = "prototype")
    public Person person() {
        return new Person();
    }
}

2.5)@Conditional makes conditional judgment, etc

         In the scenario, there are two components, TulingAspect and TulingLog. My tulingalog component is a component that depends on TulingAspect

         Application: create a turingcondition class to implement the Condition interface

public class TulingCondition implements Condition {

    /**
     *
     * @param context
     * @param metadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //Determine whether there are tulingAspect components in the container
        if(context.getBeanFactory().containsBean("tulingAspect")) {
            return true;
        }
        return false;
    }
}



public class MainConfig {

    @Bean
    public TulingAspect tulingAspect() {
        return new TulingAspect();
    }

    @Bean
    @Conditional(value = TulingCondition.class)
    public TulingLog tulingLog() {
        return new TulingLog();
    }
}

2.6) method of adding components to IOC container

① : through @ compentscan + @ controller @ service @ repository @ compent applicable scenario: components written by ourselves can be loaded into the container in this way.

② : import components through @ Bean (applicable to classes importing third-party components)

③ : Import components through @ Import (the id of the imported component is the full class name path)

@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig {
}

         Import components through the ImportSeletor class of @ import (the id of the imported component is the full class name path)

public class TulingImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.tuling.testimport.compent.Dog"};
    }
}

@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class})
public class MainConfig {
}

         Import the component through the ImportBeanDefinitionRegister of @ import (you can specify the name of the bean)

public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
        registry.registerBeanDefinition("cat",rootBeanDefinition);
    }
}

@Configuration
//@Import(value = {Person.class, Car.class})
//@Import(value = {Person.class, Car.class, TulingImportSelector.class})
@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})
public class MainConfig {
}

         ④ : implement the registration component by implementing the factorybean interface

/**
 * Register components in the container by implementing the factoryBean interface
 */
public class CarFactoryBean implements FactoryBean<Car> {

    @Override
    public Car getObject() throws Exception {

        return new Car();
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

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


@Configuration
@ImportResource(locations = {"classpath:beans.xml"})
public class MainConfig {

    @Bean
    public CarFactoryBean carFactoryBean() {
        return new CarFactoryBean();
    }
}

2.7) Bean initialization method and destruction method

① : what is the lifecycle of a bean?

         bean creation - > initialization - > destruction method

The container manages the life cycle of beans. We can specify the initialization method and destruction method of beans by ourselves

@Configuration
@ComponentScan(basePackages = "com.tuling.testbeanlifecycle")
public class MainConfig {

    @Scope(value = "prototype")
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }


}

         For single instance beans, when the container starts, the bean object is created, and when the container is destroyed, the bean destruction method will also be called.

         For multi instance beans, the beans will not be created when the container starts, but will be created when the beans are obtained, and the destruction of beans is not managed by the IOC container (JVM)

② : the initialization and destruction methods of beans are implemented through the two interfaces of InitializingBean and DisposableBean

public class TulingLog implements InitializingBean {


    public TulingLog() {
        System.out.println("I am TulingLog Construction method of");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("I am TulingLog of afterPropertiesSet method");
    }


    public void init() {
        System.out.println("I am tulinglog of init method");
    }
}

③ : annotation method of @ PostConstruct and @ ProDestory provided by JSR250 specification

@Component
public class Book {

    public Book() {
        System.out.println("book Construction method of");
    }

    @PostConstruct
    public void init() {
        System.out.println("book of PostConstruct Marking method");
    }

    @PreDestroy
    public void destory() {
        System.out.println("book of PreDestory Annotation method");
    }
}

④ : the post processor of beans through Spring's BeanPostProcessor will intercept all bean creation processes

         postProcessBeforeInitialization is called before the init method.

         postProcessAfterInitialization is called after the init method.

@Component
public class TulingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("TulingBeanPostProcessor...postProcessBeforeInitialization:"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("TulingBeanPostProcessor...postProcessAfterInitialization:"+beanName);
        return bean;
    }
}

    2.8) assign values to components through @ Value +@PropertySource

@Configuration
@PropertySource(value = {"classpath:person.properties"})
public class MainConfig {

    @Bean
    public Person person() {
        return new Person();
    }
}


person.lastName=Old thief

2.9) automatic assembly

        @ Use of AutoWired

//A Dao 
@Repository 
public class TulingDao { 
}

@Service 
public class TulingService { 
    @Autowired private TulingDao tulingDao;
}

Conclusion:

         a: Automatic assembly is first assembled according to the type. If multiple components of the same type are found in the IOC container, it is assembled according to the attribute name

        @Autowired private TulingDao tulingDao;

         For example, there are two tulingDao components in my container, one is tulingDao and the other is tulingDao2. If we modify the attribute name through @ AutoWired, then the tulingDao component of the container will be loaded. If the attribute name is tulingDao2, then the tulingDao2 component will be loaded.

         b: Assuming that we need to specify specific components for assembly, we can specify the assembled components by using @ qualifier ("turingdao"), or add @ Primary annotation to the @ Bean on the configuration class

    @Qualifier(value = "tulingDao5")
    @Autowired
    private TulingDao tulingDao2;

        c: Assuming that there are no tulingDao2 and tulingDao5 in our container, an exception will be thrown during assembly

          If we don't want to throw exceptions, we need to specify required as false

    @Qualifier(value = "tulingDao5")
    @Autowired(required = false)
    private TulingDao tulingDao2;

         d:@Resource(JSR250 specification)

         The function is almost the same as that of @ AutoWired, but @ Primary and @ Qualifier are not supported

         e:@InJect (JSR330 specification)

         You need to import jar package dependent functions and support @ Primary functions, but there is no function of Require=false

         f: Use autowired to label on methods

         Label on set method

    @Autowired
    public void setTulingLog(TulingLog tulingLog) {
        this.tulingLog = tulingLog;
    }

         Label on construction method

    @Autowired
    public TulingAspect(TulingLog tulingLog) {
        this.tulingLog = tulingLog;
    }

3.0) when our own components need to use the underlying components of spring ioc, such as ApplicationContext

         We can implement it by implementing XXXAware interface.

@Component
public class TulingCompent implements ApplicationContextAware,BeanNameAware {

    private ApplicationContext applicationContext;

    @Override
    public void setBeanName(String name) {
        System.out.println("current bean name is :["+name+"]");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

3.1) activate and identify different beans according to the environment through @ Profile annotation

  •         @ If the Profile is identified on the class, the entire configuration class will take effect only if the current environment matches
  •         @ If the Profile is identified on the Bean, only the Bean of the current environment will be activated

No bean marked @ Profile can be activated in any environment

@Configuration
@PropertySource(value = {"classpath:ds.properties"})
public class MainConfig implements EmbeddedValueResolverAware {

    @Value("${ds.username}")
    private String userName;

    @Value("${ds.password}")
    private String password;

    private String jdbcUrl;

    private String classDriver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");
        this.classDriver = resolver.resolveStringValue("${ds.classDriver}");
    }

    @Bean
    @Profile(value = "test")
    public DataSource testDs() {
        return buliderDataSource(new DruidDataSource());
    }

    @Bean
    @Profile(value = "dev")
    public DataSource devDs() {
        return buliderDataSource(new DruidDataSource());
    }

    @Bean
    @Profile(value = "prod")
    public DataSource prodDs() {
        return buliderDataSource(new DruidDataSource());
    }

    private DataSource buliderDataSource(DruidDataSource dataSource) {
        dataSource.setUsername(userName);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(classDriver);
        dataSource.setUrl(jdbcUrl);
        return dataSource;
    }
}

         How to activate the switching environment:

  •          Switch - Dspring.profiles.active=test|dev|prod through the runtime jvm parameter
  • Activated by code
public class MainClass {

    public static void main(String[] args) {
/*        AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(MainConfig.class);*/

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        //ctx.getEnvironment().setActiveProfiles("test","dev");

        ctx.register(MainConfig.class);
        ctx.refresh();
        printBeanName(ctx);
    }

    private static void printBeanName(AnnotationConfigApplicationContext ctx){
        for(String beanName:ctx.getBeanDefinitionNames()) {
            System.out.println("In container BeanName: "+beanName);
        }
    }

}

Posted by benutne on Sun, 24 Oct 2021 20:04:10 -0700