Chapter 01 Spring Foundation and Component Usage

What is Section 01-Spring?

Spring focuses on J2EE solutions, not just one layer of solutions. Spring is a “one-stop shop” for enterprise application development, spanning the presentation, business, and persistence layers. However, Spring does not want to replace existing frameworks, but rather integrate them with a high degree of openness.

Spring used IoC container and DI dependency injection most early. By configuring bean tags in the application. XML file, components or objects in the project are handed over to the IoC container for management. This results in a large project with a large number of bean tags to configure, which can be cumbersome to maintain.

Spring Core Architecture

  • Spring Core: That is, the Spring Core, which is the most basic part of the framework and provides IOC and dependency injection features
  • Spring Context: That is, the Spring Context container, which is a BeanFactory enhanced subinterface
  • Spring Web: It provides support for Web application development
  • Spring MVC: It is an implementation of the MVC idea in Web applications
  • Spring DAO: Provides an abstraction layer for JDBC, simplifying JDBC coding and making coding more robust.
  • Spring ORM: It supports integration for popular ORM frameworks such as Spring + Hibernate, Spring + iBatis, Spring + JDO integration, and so on.

Common Spring Components

Section 02 – XML and annotation register beans

Create maven project, add dependency add Entity package, add entity class Person

public class Person {
    private String name;
    private Integer age;
    / / omit getter/setter/toString
}
Copy the code

XML configuration register beans

Create a new beans.xml configuration file in the Resource directory


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.citi.entity.Person">
        <property name="name" value="Peter"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>
Copy the code

Create a new SingleBeanContainerTest test class under Test Pacakge, add the main method, and call getBeanByXml() to test getting the bean from the container

public static void getBeanByXml(a){
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
    Person person = (Person) context.getBean("person");
    System.out.println(person);
}
Copy the code

Console printing

Add the configuration class BeanConfig to the config package by registering beans with annotations

@Configuration
public class BeanConfig {

    @Bean
    public Person person(a){
        Person person = new Person();
        person.setName("Stark");
        person.setAge(40);
        returnperson; }}Copy the code

@configuration: identifies a Configuration class, which is equivalent to a Configuration file. @bean: Registers a Bean to the container with the type of the returned value and the id of the returned value SingleBeanContainerTest. The new method is executed in the main method

public static void getBeanByAnno(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); Person person = (Person) context.getBean("person"); System.out.println(person); String[] beanNamesForType = context.getBeanNamesForType(Person.class); for (String s : beanNamesForType) { System.out.println("Bean id:" + s); }}Copy the code

Console output

Change the method name of the @bean annotation in BeanConfig to stark

@Bean
public Person stark(a){
    Person person = new Person();
    person.setName("Stark");
    person.setAge(40);
    return person;
}
Copy the code

Error: No bean named ‘person’ available

“Person” = “person”; “person” = “stark”; “person” = “person”; “stark” = “person”

In addition to changing the method name under the @bean annotation to define the Bean ID, you can also define the Bean name by @bean (“thor”)

Add data to the Map using put(“key”,value). Key is the id of the Bean. Value is the object.

Section 03 – BATCH register beans with annotations

@compponmentScan replaces @bean to add controller, Service and DAO packages respectively and add responding classes. The three classes are declared as beans by @Controller, @Service and @repository annotations

@Controller
public class PersonController {}Copy the code
@Service
public class PersonService {}Copy the code
@Repository
public class PersonDao {}Copy the code

Add the @ComponentScan annotation to BeanConfig to scan all the beans under the com.citi package into the BeanConfig configuration class. This is equivalent to having many Bean tags in an XML configuration file. All beans can be scanned with a single annotation

@Configuration
@ComponentScan(basePackages = "com.citi")
public class BeanConfig {

}
Copy the code

Add a New ComponentScanTest test class to test whether the IoC container instantiates scanned beans

public class ComponentScanTest {

    @Test
    public void getBeansByScan(a){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for(String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); }}}Copy the code

The console output is as follows: the three custom classes, including BeanConfi itself, are instantiated by the container

The Person class in the Entity package is not instantiated because there is no annotation on the Person class, so it is not registered in the container and therefore is not instantiated. Add an @Component annotation to the Person entity class to identify it as a bean. The test method is executed again, and the console prints the following result, with the Person class instantiated

@ ComponentScan source

The use of includeFilters ()

IncludeFilters () and excludeFilters() return a Filter array

FilterType is an enumerated class, default is ANNOTATION, ANNOTATION mode

Modify the BeanConfig code and add includeFilters() to scan only beans identified by the @controller, @service annotation below the com.citi package. Don’t forget to useDefaultFilters = false

@Configuration
@ComponentScan(basePackages = "com.citi", includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}) }, useDefaultFilters = false)
public class BeanConfig {}Copy the code

When the test is executed, the console outputs only beans with @Controller, @Service annotations, @Componet, and @Repository annotations that are not container-managed

Plus: Why useDefaultFilters = false when using includeFilters?

When useDefaultFilters = true, it goes into the registerDefaultFilters() method

This method adds the @Component-annotated beans into the includeFilters, while @controller, @Service, and @Repository are all based on @Component annotations. All useDefaultFilters = true will cause beans set to scan for @Controller and @Service annotations not to take effect

Set BeanConfig includeFilters () to excludeFilters() and useDefaultFilters = true. Instantiation object of a Bean other than the @service annotated Bean

Filter beans using ASSIGNABLE_TYPE in the FilterType enumerated class and modify BeanConfig to the following to indicate that beans other than PersonController and PersonService are being accessed

@Configuration
@ComponentScan(basePackages = "com.citi", excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonController.class, PersonService.class}) }, useDefaultFilters = true)
public class BeanConfig {}Copy the code

Using a custom FilterType, CustTypeFilter is added to the config package, inheriting TypeFilter

public class CustTypeFilter implements TypeFilter {

    / * * *@paramMetadataReader reads information about the class currently being scanned *@paramMetadataReaderFactory can get information for any other class *@return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // Get the annotation information for the current class
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // Get information about the classes currently being scanned
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // Get the current class resource (class path)
        Resource resource = metadataReader.getResource();

        // Get the class name
        String className = classMetadata.getClassName();
        // Scan the class
        System.out.println("-- -- -- -- -- - >" + className);

        Return true to filter out beans that meet this condition
        if (className.contains("service")) {return true;
        }
        return false; }}Copy the code

In addition to @ComponentScan, you can also add @ComponentScans

Two @ComponentScan annotations are used, one to remove custom beans whose Bean ID contains the “service” string, and the other to remove beans marked with the @Controller Annotation using the Filter Annotation type

@ComponentScans({@ComponentScan(basePackages = "com.citi", excludeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustTypeFilter.class}) }, useDefaultFilters = true), @ComponentScan(basePackages = "com.citi", excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) }, useDefaultFilters = true)})

public class BeanConfig {}Copy the code

The console should output an instantiated object with the exception of PeresonController and PersonService. According to the console print, the two @ComponentScan configurations are not in effect.

Section 04-bean single-instance and multi-instance

IoC containers, whether annotated or XML, are single-instance by default and are created when the IoC container is initialized. Multi-instances are created only when the bean is used

@Configuration
public class BeanConfig {

        @Bean
        public Person person(a){
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                returnperson; }}Copy the code

New test class SingleOrMultInstanceTest, perform testSingleBean () method

public class SingleOrMultiInstanceTest { @Test public void testSingleBean(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); Person person = (Person) context.getBean("person"); Person person1 = (Person) context.getBean("person"); System.out.println(" single instance: "+ (person == person1)); }}Copy the code

View the output by comparing the two beans retrieved from the container to see if they are one bean, which is singleton by default

The @scope annotation allows you to configure a Bean to be single-instance or multi-instance

Modify BeanConfig

@Configuration
public class BeanConfig {

        @Bean
        @Scope("prototype")
        public Person person(a){
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                returnperson; }}Copy the code

Execute the test, which is now multi-instance

Section 05 – Lazy loading @Lazy

Modify BeanConfig to add @lazy annotation, Lazy loading pointer to multi-singleton Bean, because singleton is created when container initialization, add @lazy annotation, The container instantiates the Bean when it calls getBean() to get the instantiated object first annotating the @Scope annotation in BeanConfig

@Configuration
public class BeanConfig {

        //@Lazy
        @Bean
        //@Scope("prototype")
        public Person person(a){
                System.out.println("Bean is instantiated");
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                returnperson; }}Copy the code

New LazyLoadTest, testLazyLoad() method that contains only container initialization code

public class LazyLoadTest {

    @Test
    public void testLazyLoad(a){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        //Person person = (Person) context.getBean("person");
        //System.out.println(person);}}Copy the code

Looking at the console, the Bean is instantiated, indicating that the Bean is instantiated when the container is initialized

Release the @lazy annotation in BeanConfig, and again, the Bean is not instantiated

Add the code to get the Bean in the testLazyLoad() method of the LazyLoadTest class

public class LazyLoadTest {

    @Test
    public void testLazyLoad(a){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        Person person = (Person) context.getBean("person"); System.out.println(person); }}Copy the code

After the @lazy annotation is added, the container initializes the Bean instead of instantiating it on getBean