I. Introduction to the overall functions of Spring Framework

The Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure, so you can focus on your application.

Spring allows you to build applications from plain old Java objects (POJos) and apply enterprise services to POJOs in a non-intrusive manner. This functionality applies to the Java SE programming model as well as to full and partial Java EE.

Here are some examples of how you, as an application developer, can benefit from the Spring platform:

  • Enables Java methods to execute in database transactions without having to deal with transaction apis.
  • Make local Java methods remote procedures without having to deal with remote apis.
  • Make native Java methods administrative operations without having to deal with JMX apis.
  • Make native Java methods a message handler without having to deal with the JMS API.

The Spring Framework consists of about 20 modules of functionality. These modules are divided into core containers, data access/integration, Web, AOP (aspect-oriented programming), instrumentation, messaging, and testing, as shown in the figure below.

1. Spring Core Container

What modules do: Core and Beans modules are the foundation of the framework and provide IoC and dependency injection features. The basic concept here is BeanFactory, which provides a classical implementation of the Factory pattern to eliminate the need for a programmatic singleton pattern and really allows you to separate dependencies and configurations from program logic.

1.1 the Core

This package contains the basic Core utility classes of the Spring framework, which are used by other Spring components. The Core module is the basic Core of other components.

1.2 Beans (BeanFacotry)

It contains all classes for accessing configuration files, creating and managing beans, and doing Inversion of Control I Dependency Injection (IoC/DI) operations.

1.3 Context(BeanFactory or ApplicationContext)

Built on Core and Beans modules, it provides a framework like JNDI register-like object access method. The Context module inherits Beans features and provides a number of extensions to the Spring core, adding support for internationalization (such as resource binding), event propagation, resource loading, and transparent creation of the Context. The Context module also supports some features of J2EE. The ApplicationContext interface is the key to the Context module

Essential difference :(beans that use BeanFacotry are loaded lazily,ApplicationContext is loaded non-lazily)

1.4 Expression Language

Modules provide 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/getting attribute values, assigning attributes, calling methods, Accessiong the Context of Arrays, containers and indexers, logical and arithmetic operators, named variables, and objects by name from Spring’s IoC container. It also supports list projection, selection, and general list aggregation

2. Spring Data Access/Integration

2.1 the JDBC

The module provides a JDBC abstraction layer that eliminates verbose JDBC coding and error code specific to database vendors. This module contains all the classes that Spring encapsulates for JDBC data access

2.2 ORM module is a popular object-relational mapping API

JPA, JDO, Hibernate, MyBatis, etc., provide an interaction layer. With ORM packages, you can mix all the features Spring provides for O/R mapping, such as simple declarative transaction management.

2.3 THE OXM module provides an abstraction layer for the ObjecνXML mapping implementation

Object/XML mapping implementations include JAXB, Castor, XMLBeans, JiBX, and XStrearn

2.4 Java Messaging Service (JMS)

The module mainly contains features for making and consuming messages.

2.5 the Transaction

Support for programmatic and declarative transaction management, which must implement specific interfaces and be applicable to all POJOs

3. Spring Web

Web module: Provides basic Web-oriented integration features. For example, multiple file uploads and Servlet Listeners are initialized

The IoC container and a Web-oriented application context. It also includes web-related parts of Spring’s remote support.

4. Spring Aop

  • The Aspects module provides integration support for AspectJ.
  • The Instrumentation module provides class Instrumentation support and a ClassLoader implementation that can be used on specific application servers

5. Spring Test

The Test module supports testing of Spring components using JUnit and TestNG

6. Spring container inheritance diagram

7. Inversion of control and dependency injection

What is inversion of control?

It is important to understand an important idea of software design: Dependency Inversion Principle.

What depends on the inversion principle? Suppose we design a car: design the wheels first, then design the chassis according to the size of the wheels, then design the body according to the bottom plate, and finally design the whole car according to the body. Here comes a “dependency” relationship: the car depends on the body, the body depends on the chassis, and the chassis depends on the wheels

What does the picture look like? But if the tire size is changed, then the site needs to be changed, the site is changed, the body is changed, so that the whole structure of the car is changed. Then the car company went bankrupt………………….

The chairman of the board depends on the general manager to make money, the general manager depends on the department manager to make money, the department manager depends on the employee to fight for, so how to do the employee quit??????????

In turn… If the car company decides to change the tire, we only need to change the design of the wheel, without moving the chassis, the body, the design of the car.

The core of the IOC philosophy is that resources are not managed by the two parties who use them, but by a third party who does not use them. This can bring many benefits, as follows:

  • Centralized resource management enables easy configuration and management of resources
  • It reduces the dependence of both parties using the resource, which is called coupling degree

2. Use of the underlying annotations of the Spring IOC container

XML configuration file form VS configuration class form

1 Defining Bean information based on XML form

<? 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"// Define information for a Bean < Bean id="car" class="com.niuh.compent.Car"></bean>
</beans>
Copy the code

Go to the container and read the Bean

public static void main( String[] args ) {
   ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
   System.out.println(ctx.getBean("person")); 
}
Copy the code

Define Bean information based on the form of read configuration class

@Configuration
public class MainConfig {
    @Bean
    public Person person() {returnnew Person(); }}Copy the code

Note: The default name of the Bean is the method name when used in the @bean form. If @bean (value=” Bean name “) then the name of the Bean is specified

Read Bean information from container (passing in configuration class)

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

Write the @compentScan annotation on the configuration class to perform packet scanning

@Configuration
@ComponentScan(basePackages = {"com.niuh.testcompentscan"}) 
public class MainConfig {
}
Copy the code

1 excludeFilters (excluding @controller annotated and NiuhService)

@Configuration
@ComponentScan(basePackages = {"com.niuh.testcompentscan"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {NiuhService.class}) })
public class MainConfig {
}
Copy the code

1 includeFilters note: To use includeFilters, set useDefaultFilters property to false (true means scan all)

@Configuration
@ComponentScan(basePackages = {"com.niuh.testcompentscan"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}) },useDefaultFilters = false)
public class MainConfig {
}
Copy the code

3 the type of ComponentScan.Filter type

ANNOTATION @controller @service @repository @compent * Specifies the type of filterType. ASSIGNABLE_TYPE @ComponentScan.Filter(type= filterType.assignable_type,value = {niuhservice.class})}) * AspectJ type of filtertype.aspectj (not commonly used) * regular expression Filtertype.regex (uncommon) * CUSTOM filtertype.customCopy the code
Public enum FilterType {// The ANNOTATION form is @controller@servicer@repository @compent ANNOTATION, // the specified type is ASSIGNABLE_TYPE, //aspectJ form of aspectJ, // regular expression REGEX, // CUSTOM}Copy the code

Filtertype. CUSTOM How to use a CUSTOM type

public class NiuhFilterType implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory MetadataReaderFactory) throws IOException {// Get AnnotationMetadata AnnotationMetadata = metadataReader.getAnnotationMetadata(); / / get the current class of class source information ClassMetadata ClassMetadata = metadataReader. GetClassMetadata (); / / get the current class of Resource information Resource Resource. = metadataReader getResource ();if(classMetadata.getClassName().contains("dao")) { 
            return true;
       }
       return false; 
    }
}

@ComponentScan(basePackages = {"com.niuh.testcompentscan"},includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,value = NiuhFilterType.class)},useDefaultFilters = false)
public class MainConfig {
}
Copy the code

3. Configure the Bean’s scope object

1 Without specifying @scope, all beans are single-instance beans and are hungry loading (start start instance is created)

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

2 Specifying @scope as prototype means multi-instance and lazy loading mode (when IOC container is started, objects will not be created, but on the first use)

@Bean
@Scope(value = "prototype") 
public Person person() {
    return new Person(); 
}
Copy the code

3 Value of Scope method specified on 3

  • Singleton single instance (default)
  • Prototype multi-instance
  • Request Indicates the same request
  • Session Indicates the same session level

Lazy loading of beans @lazy

For single-instance beans, no object is created when the container is started, but only when it is used for the first time

@Bean
@Lazy
public Person person() {
    return new Person(); 
}
Copy the code

5. @Conditional makes Conditional judgments, etc

Scenario, there are two components NiuhAspect and NiuhLog, my NiuhLog component is a component application that depends on NiuhAspect: I create a NiuhCondition 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 containerif(context.getBeanFactory().containsBean("tulingAspect")) {
            return true; 
        }
        return false; 
    }
}

public class MainConfig {
    @Bean
    public NiuhAspect niuhAspect() {
        returnnew NiuhAspect(); } @bean@conditional (value = niuhcondition.class) public niuhLog @bean@conditional (value = niuhcondition.class) public niuhLogniuhLog() {
        returnnew NiuhLog(); }}Copy the code

6. Ways to add components to IOC containers

1 one via @compentScan + @controller @service @respository @compent

Application scenario: Components written by ourselves can be loaded into containers in this way.

2 Discount on the import of components via @bean (applicable to the import of tears of third-party components)

3 Import components via @import (ID of Import component is path of full class name)

@Configuration
@Import(value = {Person.class, Car.class}) 
public class MainConfig {
}
Copy the code
  • Import components with the @import ImportSeletor class (the id of the imported component is the full class name path)
Public class NiuhImportSelector implements ImportSelector {@override public String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.niuh.testimport.compent.Dog"}; 
    }
} 

@Configuration
@Import(value = {Person.class, Car.class, NiuhImportSelector.class}) 
public class MainConfig {
}
Copy the code
  • Through the @ Import ImportBeanDefinitionRegister Import components (can specify the name of the bean)
public class NiuhBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// Create a bean definition object RootBeanDefinition RootBeanDefinition = new RootBeanDefinition(Cat.class); / / define the bean object into the container 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, NiuhImportSelector.class, NiuhBeanDefinitionRegister.class}) 
public class MainConfig {
}
Copy the code

4 Discount is realized by implementing FactoryBean interface

Public class CarFactoryBean implements FactoryBean<Car> {// Return bean object @override public Car getObject() throws Exception {returnnew Car(); } @override public Class<? >getObjectType() {
        returnCar.class; } // Whether this is a singleton @override public BooleanisSingleton() {
        return true; }}Copy the code

7. Bean initialization and destruction methods

1 What is Bean’s life cycle?

Bean creation ——-> initialize ———> Destroy method

The container manages the Bean life cycle, and we can specify the Bean initialization method and Bean destruction method ourselves

@configuration public class MainConfig {// Specifies the life cycle of the bean initialization method and destruction method"init",destroyMethod = "destroy") 
    public Car car() {
        returnnew Car(); }}Copy the code

For single-instance beans, when the container is started, the bean object is created, and when the container is destroyed, the bean’s destruction method is called

In the case of multi-instance beans, the bean is not created when the container is started but when the bean is retrieved, and bean destruction is not managed by the IOC container.

One of the two interfaces of InitializingBean and DisposableBean to implement the bean initialization and destruction method

@Component
public class Person implements InitializingBean,DisposableBean {
    public Person() { 
        System.out.println("Constructor of Person");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean's destroy() method"); 
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("AfterPropertiesSet method for InitializingBean"); }}Copy the code

3 Method of annotation @postconstruct and @Prodestory annotation provided by JSR250 specification

@Component
public class Book {
    public Book() {
        System.out.println("Constructor of book");
    }
    
    @PostConstruct 
    public void init() {
        System.out.println("Method of PostConstruct flag for book"); 
   }
   
    @PreDestroy
    public void destory() {
        System.out.println("Method of PreDestory annotation in Book"); }}Copy the code

A postprocessor of the bean through Spring’s BeanPostProcessor intercepts all bean creation

PostProceessBeforInitialization before the init method call

PostProcessAfterInitialization called after the init method

@Component
public class NiuhBeanPostProcessor 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);
        returnbean; }}Copy the code

Execution time of BeanPostProcessor

populateBean(beanName, mbd, instanceWrapper) initializeBean{ applyBeanPostProcessorsBeforeInitialization() invokeInitMethods{ IsInitializingBean. AfterPropertiesSet custom method init} applyBeanPostProcessorsAfterInitialization} () methodCopy the code

Assign values to components via @Value + @propertysource

Public class Person {// @value ();"A dime.") private String firstName; // assign @value (spel)28 "# {8}") private Integer age; By reading @value from the external configuration file ("${person.lastName}") 
   private String lastName;
}

@Configuration
@PropertySource(value = {"classpath:person.properties"Public class MainConfig {@bean public Personperson() {
        returnnew Person(); }}Copy the code

9, automatic assembly

The use of the @autowired

Automatic injection:

Public class NiuhDao {} @service public class NiuhService {@autoWired private NiuhDao NiuhDao; }Copy the code

Conclusion:

1 Automatic assembly is firstly assembled according to type. If multiple components of the same type are found in IOC container, assembly will be carried out according to the attribute name

@Autowired

private NiuhDao niuhDao;
Copy the code

For example, there are two NiuhDao type components in the container, one named NiuhDao and one named niuhDao2

The niuhDao component of the container will be loaded if the property name is niuhDao2 or niuhDao2.

2 Assuming that we need to specify a specific component for assembly, we can specify the assembly component by using @qualifilter (“niuhDao”) or annotating @primary on the @bean on the configuration class

@Autowired 
@Qualifier("niuhDao") 
private NiuhDao niuhDao2;
Copy the code

3 One assumes that there is no niuhDao and niuhDao2 in the container, then exceptions will be thrown during assembly

No qualifying bean of type 'com.niuh.testautowired.NiuhDao' available

If we don’t want to throw exceptions, we need to specify required to be false

@Autowired(required = false)
@Qualifier("niuhDao") 
private NiuhDao niuhDao2;
Copy the code

4 Retail @Resource (JSR250 specification)

The functionality is similar to @autoWired, but @primary and @Qualifier are not supported

5 Retail @InJect (JSR330 specification)

The @primary function is supported, but Require=false is not

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
Copy the code

6 Autowired can be marked on the method

Labeled on the set method

//@Autowired
public void setNiuhLog(NiuhLog niuhLog) {
    this.niuhLog = niuhLog; 
}
Copy the code

The notation is on the constructor

@Autowired
public NiuhAspect(NiuhLog niuhLog) {
    this.niuhLog = niuhLog; 
}
Copy the code

Annotation in input parameter on configuration class (optional)

@Bean
public NiuhAspect niuhAspect(@Autowired NiuhLog niuhLog) {
    NiuhAspect niuhAspect = new NiuhAspect(niuhLog);
    return niuhAspect; 
}
Copy the code

10. When our own components need to use spring IOC’s underlying components, such as ApplicationContext, we can implement the XXXAware interface

@Component
public class NiuhCompent 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; }}Copy the code

Use the @profile annotation to activate and identify different beans depending on the environment

@profile identifies the class, so the entire configuration class takes effect only if the current environment matches

@profile identifies a Bean, so only beans in the current environment will be activated

Can beans that are not marked @profile 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 =) will be installed if it is identified as a test environment"test")
    public DataSource testDs() {
        returnbuliderDataSource(new DruidDataSource()); } // Identify the development environment is activated @bean@profile (value ="dev")
    public DataSource devDs() {
        returnbuliderDataSource(new DruidDataSource()); } // Identify the production environment is activated @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);
        returndataSource; }}Copy the code

Method to activate the switch environment

Method one: by running when the JVM parameter to switch – Dspring. Profiles. The active = test | dev | prod

Method 2: Code the activation

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); 
    ctx.getEnvironment().setActiveProfiles("test"."dev");
    ctx.register(MainConfig.class); 
    ctx.refresh(); 
    printBeanName(ctx);
}
Copy the code