From Shallow to Deep, Explain the Detailed Use of spring Actual Warfare - spring Source Chapter

Keywords: Java Spring xml encoding

First of all, this article will not go deep into the underlying source code in detail, just based on annotations and configuration to talk about the use of spring, don't underestimate the basis, to ensure that you have unused annotations and configuration, go.

Let's start with a maven project, introducing spring files, which you don't like to download at the bottom of the article with a code address. First look, then download the code and try it yourself. Let's give it to you first. Try it and watch it.

1. Basic XML Injection Bean

<?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.springIOC.bean.CarBean"></bean>
</beans>
package com.springIOC;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("config.xml");
        Object car = cac.getBean("car");
    }
}

Is it super simple? Let's go from shallow to deep.

2. Configuration based on annotations

package com.springIOC2.config;

import com.springIOC.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean
        public CarBean car(){
        
        return new CarBean();
    }
}
package com.springIOC2;

import com.springIOC2.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
        Object car = aca.getBean("car");
    }
}

We can get our object directly by the method name, and the default is to assemble it according to the method. You can also specify the assembly name by @Bean(value="newName").

It is the golden nine silver ten job-hopping season, for you to collect the latest interview information in 2019, there are documents, strategies, videos. Students in need can receive the latest interview information strategy by sending an interview on the public number [Java bosom friend]! Don't send the code [1024], otherwise...

3. Assemble as a package scan (emphasis), using @ComponentScan (base Packages = {"full path of the package"}

package com.springIOC3.config;

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

@Configuration
@ComponentScan(basePackages = {"com.springIOC3"})
public class MainConfig {
}
package com.springIOC3;

import com.springIOC3.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = aca.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("beanDefinitionName = " + beanDefinitionName);
        }
    }
}

Here are a few parameters, excludeFilters excludes some objects, the grammar is as follows

excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),  
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {RepositoryBean.class}) 
}

There are five types of FilterType: ANNOTATION (Annotation Class), ASSIGNABLE_TYPE (Class Name), ASPECTJ (Unusual, Documentation says AspectJ Type Pattern Expression Matching), REGEX (Regular Expression Matching), CUSTOM (Custom), and three commonly used I marked red. Let's take a look at the specific writing.

package com.springIOC3b.config;

import com.springIOC3b.repository.RepositoryBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = {"com.springIOC3b"},excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {RepositoryBean.class})
}
)

public class MainConfig {
}

Just now we talked about custom filtering. Let's look at how to write custom filtering, implement our TypeFilter interface, rewrite our match es, and focus only on the returned true. Here's an example

package com.springIOC3c.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;

public class CustomFilterType implements TypeFilter {
    @Override
        public Boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        
        Resource resource = metadataReader.getResource();
        if (classMetadata.getClassName().contains("RepositoryBean")) {
            
            return true;
        }
        
        
        
        return false;
    }
}

In contrast to inclusion, we only allow what to be introduced, that is, our includeFilters, and we need to pay attention to the need to set the useDefaultFilters property to false(true for all scans). The grammar is exactly the same as excludeFilters

package com.springIOC3d.config;

import com.springIOC3d.service.ServiceBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = {"com.springIOC3d"},includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = ServiceBean.class)
}
,useDefaultFilters = false)

public class MainConfig {
}

4. Looking back, let's look at the scope of beans.

@ Lazy lazy loading, use to instantiate, look at the code, we add a construction method in the Bean, more convenient to determine when to instantiate.

package com.springIOC4.config;

import com.springIOC4.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class MainConfig {
    @Bean
        @Lazy
        public CarBean car(){
        return new CarBean();
    }
}

Specify that @Scpoe can have four scopes

(a) singleton single instance (default). The lifecycle of a singleton is controlled by a spring container. Objects are generated after spring instantiation when non-lazy loading occurs, and object destruction occurs when container destruction occurs.

package com.springIOC4b.config;

import com.springIOC4b.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

@Configuration
public class MainConfig {
    @Bean
        @Scope(value = "singleton")
        public CarBean car(){
        return new CarBean();
    }
}
package com.springIOC4b;

import com.springIOC4b.bean.CarBean;
import com.springIOC4b.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
        CarBean car = (CarBean)aca.getBean("car");
        CarBean car2 = (CarBean)aca.getBean("car");
        System.out.println(car == car2);
        
    }
}

The output is true, indicating that our object is singleton, singleton object, life cycle is managed by spring.

b) prototype multi-instance

package com.springIOC4c.config;

import com.springIOC4c.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class MainConfig {
    @Bean
        @Scope(value = "prototype")
        public CarBean car(){
        return new CarBean();
    }
}
package com.springIOC4c;

import com.springIOC4c.bean.CarBean;
import com.springIOC4c.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
        CarBean car = (CarBean)aca.getBean("car");
        CarBean car2 = (CarBean)aca.getBean("car");
        System.out.println(car == car2);
        
    }
}

Many cases are not managed by ioc containers, they are cleaned up by GC when they are destroyed, and there are requests at the same request and session at the same session level.

5.@Configuration annotation to determine whether a Bean is injected.

package com.springIOC5.config;

import com.springIOC5.bean.CarBean;
import com.springIOC5.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean(value = "user")
        public UserBean userBean() {
        return new UserBean();
    }
    @Bean
        @Conditional(value = IOCConditional.class)
        public CarBean carBean() {
        return new CarBean();
    }
}
package com.springIOC5.config;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class IOCConditional implements Condition {
    @Override
        public Boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (context.getBeanFactory().containsBean("user")) {
            
            return true;
        }
        return false;
    }
}

What does the above code mean? Is it necessary for us to inject carBean? If we include user, we inject our carBean. If not, we inject our carBean. It's interesting to note that the injections of classes in Configuration configuration are orderly. We must put our beans as judgements on them, otherwise Conditional will recognize them. You don't have Bean with that judgment.

6.@Import Introducing Bean

package com.springIOC6.config;

import com.springIOC6.bean.CarBean;
import com.springIOC6.bean.UserBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({
    CarBean.class, UserBean.class
}
)
public class MainConfig {
}

Write the class we want to inject directly into the annotation, or you can use the interface to implement it. Let's change it.

package com.springIOC6b.config;

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

@Configuration
@Import({
    ImportSelector.class
}
)
public class MainConfig {
}
package com.springIOC6b.config;

import org.springframework.core.type.AnnotationMetadata;

public class ImportSelector implements org.springframework.context.annotation.ImportSelector {
    @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{
            "com.springIOC6b.bean.CarBean","com.springIOC6b.bean.UserBean"
        }
        ;
    }
}

Implement the ImportSelector class and return the full path of the class name. Automatic assembly is based on @Import.

ImportBeanDefinition Registrar and override the registerBeanDefinitions method are also possible.

package com.springIOC6c.config;

import com.springIOC6c.bean.CarBean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

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

7. Injection through FactoryBean

package com.springIOC7.config;

import com.springIOC7.bean.UserBean;
import org.springframework.beans.factory.FactoryBean;

public class IOCFactoryBean implements FactoryBean<UserBean> {
    @Override
        public UserBean getObject() throws Exception {
        
        return new UserBean();
    }
    @Override
        public Class<?> getObjectType() {
        
        return UserBean.class;
    }
    @Override
        public Boolean isSingleton() {
        
        return true;
    }
}
package com.springIOC7.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean
        public IOCFactoryBean iocFactoryBean(){
        return new IOCFactoryBean();
    }
}
package com.springIOC7;

import com.springIOC7.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
        Object carBean = aca.getBean("iocFactoryBean");
        
        System.out.println(carBean);
        Object iocFactoryBean = aca.getBean("&iocFactoryBean");
        
        System.out.println(iocFactoryBean);
    }
}

Speaking of all the ways to add components to IOC containers, I'll conclude briefly.

  • @ Bean injection can specify four scopes, single, multiple (life cycle is not managed by IOC container), one request and one session, or lazy loading.
  • @ ComponentScan specifies the way the package is scanned to inject, using the @Controller, @Repository, @Service, @Component annotations.
  • @ Import mode injection, two implementation classes ImportSelector and ImportBean Definition Registrar.
  • @ Factory Bean, the way engineering beans can also be injected. Be careful not to take - is to get the final object, take - is to get the real beans. Three methods, one specifying object, one specifying type, and one specifying whether or not it is a singleton.

For a single instance bean, when the container starts, the bean's object is created, and when the container is destroyed, the bean's destroy method is called.

For multi-instance beans, beans are not created when the container starts, but are created when the beans are retrieved, and the destruction of beans is not managed by the IOC container.

1. Let's first look at the simplest way to specify our initialization and destruction methods with initMethod and destroyMethod.

package com.springlifeCycle1a.config;

import com.springlifeCycle1a.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean(initMethod = "init",destroyMethod = "destroy")
        public CarBean car() {
        return new CarBean();
    }
}

We are specifying our init initial method and destroy method. The order of invocation is Car's construction method, Car's init method, Car's destroy method, or you can try to use the @Lazy annotation yourself. There are code clouds that you can try on your own.

2. Initializing and destroying beans through two interfaces of Initializing bean and Disposable bean

package com.springlifeCycle2a.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class CarBean implements InitializingBean, DisposableBean {
    public CarBean() {
        System.out.println("I am Car");
    }
    public void afterPropertiesSet() {
        System.out.println("I'm initialization. init");
    }
    public void destroy() {
        System.out.println("I am destroyed. destroy");
    }
}

3. Method of annotation @PostConstruct and @ProDestory provided by JSR250 specification

package com.springlifeCycle3.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class CarBean {
    public CarBean() {
        System.out.println("I am Car");
    }
    @PostConstruct
    public void init() {
        System.out.println("I'm initialization. init--PostConstruct");
    }
    @PreDestroy
    public void destory() {
        System.out.println("I am destroyed. destroy--PreDestroy");
    }    
}

4. The post-processor of beans through Spring's BeanPostProcessor will block all beans creation process (I will talk about internal implementation when I talk about source code later in this method, and I think it's necessary to look at the source code of this method).

package com.springlifeCycle4.bean;

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

@Component
public class LifeBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Initialization method" + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Destruction method" + beanName);
        return bean;
    }
}

In summary, there are four ways to specify initialization and destruction methods for objects in containers

  • Initialization and destruction methods are given with initMethod and destroyMethod of @Bean.
  • Initializing and destroying beans are realized through two interfaces of Initializing bean and Disposable bean.
  • The method of annotation @PostConstruct and @ProDestory provided by JSR250 specification.
  • The post-processor of beans through Spring's BeanPostProcessor intercepts all bean creation processes.

There aren't many things here, so I'll talk about it as soon as possible. There are three ways to assign values. Let's take a look at them.

package com.springValue.config;

import com.springValue.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value = "classpath:carBean.properties",encoding = "utf-8") //Specify the location of external files
public class MainConfig {
    @Bean
    public CarBean carBean() {
        return new CarBean();
    }
}
import org.springframework.beans.factory.annotation.Value;

public class CarBean {
    @Value("BMW")
    private String name;
    @Value("#{5-2}")
    private int carNum;
    @Value("${carBean.realName}")
    private String realName;        
}

It is worth mentioning here that it is better to set encoding = UTF-8 for importing files, otherwise Chinese characters will be scrambled.

Active assembly is usually the most familiar and used by us. Let's review it.

1.@Autowired auto-assembly is first assembled according to type. If multiple components of the same type are found in the IOC container, then they are assembled according to the attribute name.

package com.springxAutowired1.config;

import com.springxAutowired1.dao.AutowiredDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.springxAutowired1.service")
public class MainConfig {
    @Bean
    public AutowiredDao autowiredDao1(){
        return new AutowiredDao(1);
    }
    @Bean
    public AutowiredDao autowiredDao2(){
        return new AutowiredDao(2);
    }
}
package com.springxAutowired1.service;

import com.springxAutowired1.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ServiceBean {
    @Autowired
    private AutowiredDao autowiredDao2;
    public ServiceBean() {
        System.out.println("I am serviceBean");
    }
    @Override
    public String toString() {
        return "ServiceBean{" +
                "AutowiredDao=" + autowiredDao2 +
                '}';
    }
}

Here we set up two AutowiredDao objects, one identified as 1 and one identified as 2. ServiceBean is assembled by default by name.

2. We can also specify the assembly name by @Qualifier.

package com.springxAutowired1b.service;

import com.springxAutowired1b.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class ServiceBean {
    @Autowired
    @Qualifier(value = "autowiredDao1")
    private AutowiredDao autowiredDao2;
    public ServiceBean() {
        System.out.println("I am serviceBean");
    }
    @Override
    public String toString() {
        return "ServiceBean{" +
                "AutowiredDao=" + autowiredDao2 +
                '}';
    }
}

3. We use Qualifier if the name is written incorrectly, the assembly error may be wrong, then we can use required = false to prevent exception throwing.

package com.springxAutowired3.service;

import com.springxAutowired3.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class ServiceBean {
    @Qualifier(value = "autowiredDaoError")
    @Autowired(required = false)
    private AutowiredDao autowiredDao2;
    public ServiceBean() {
        System.out.println("I am serviceBean");
    }
    @Override
    public String toString() {
        return "ServiceBean{" +
                "AutowiredDao=" + autowiredDao2 +
                '}';
    }
}

Note: I'm not talking about the @Resource annotation here. It's not in spring, but in JSR250, but it doesn't support @Primary and @Qualifier.

Sometimes we need to switch our configuration through different environments. We use the @Profile annotation to activate and identify different beans according to the environment.

@ Profile is identified on the class, so the entire configuration class will take effect only if the current environment matches.

@ Profile is identified on the Bean, so only the Bean in the current environment will be activated

package com.springxAutowired4.config;

import com.springxAutowired4.bean.Environment;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class MainConfig {
    @Bean
    @Profile(value = "test")
    public Environment environment_test() {
        return new Environment("test");
    }
    @Bean
    @Profile(value = "dev")
    public Environment environment_dev() {
        return new Environment("dev");
    }
    @Bean
    @Profile(value = "pro")
    public Environment environment_pro() {
        return new Environment("pro");
    }
}

Method of Activating Switching Environment

  • Method 1: Switch the - Dspring. profiles. active = test, dev, and prod parameter tables by running jvm parameters. Use English commas to separate the tables.
  • Method 2: Activate by code
package com.springxAutowired4;

import com.springxAutowired4.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    /**
     * Environment switching
     * @param args
     */
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext();
        aca.getEnvironment().setActiveProfiles("test","dev");//Convenient demonstration, I wrote two, usually one.
        aca.register(MainConfig.class);
        aca.refresh();
        for (String beanDefinitionName : aca.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

If both are written, the parameters will no longer work as implemented in the code

"No steps, no miles." Hope you can: Dreams are everywhere for horses! Come on, boy!

Pay attention to the public number "Java bosom friend", update Java knowledge every day, look forward to your arrival!

  • Send "Group" and make progress with 100,000 programmers.
  • Send "interview" and get BATJ interview information and interview video introduction.
  • Send "Play Algorithms" and receive a series of video tutorials of "Play Algorithms".
  • Never send "1024".

Posted by daveyboy on Tue, 24 Sep 2019 20:42:37 -0700