Tong Gang Spring 4.0 study notes

 

1 Overview

Spring is an open source framework in the Java field. It is born to simplify the development of enterprise-level applications. It can use simple JavaBeans to implement functions that only EJB can achieve before.

1.1. Features

  1. Lightweight (non-intrusive): When developing based on Spring, we do not need to implement any interface provided by Spring, nor do we need to inherit any class provided by Spring, and then we can use the functions provided by Spring to us
  2. One-stop framework: On the basis of IOC, various enterprise-level open source frameworks and excellent third-party class libraries can be integrated
  3. Component composition: Spring implements the composition of a complex application using simple components, which can be composed using XML and Java annotations

1.2. Modules

1.3. Configuration files

A typical Spring project needs to create one or more bean configuration files, which can be placed in the classpath or in other directories.

2. Hello World

HelloWorld.java

package org.lin.stu.spring;

public class HelloWorld {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void say() {
        System.out.println("Hello " + name);
    }
}

2.1. Traditional way

//创建HelloWorld的一个对象
HelloWorld helloWorld = new HelloWorld();
//为name属性赋值
helloWorld.setName("World");
//调用方法
helloWorld.say();//Hello World

2.2. Using Spring

<?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">
    
    <!--初始化IOC容器时,Spring会调用HelloWorld.java的无参构造创建名为helloWorld的对象,然后调用setName(String name)方法为name属性赋值-->
    <bean id="helloWorld" class="org.lin.stu.spring.HelloWorld">
        <!--name属性值为setter风格的属性名-->
        <property name="name" value="World"/>
    </bean>
</beans>
//创建Spring的IOC容器,ClassPathXmlApplicationContext表示配置以XML文件的形式存放在类路径下
//创建IOC容器后会立即初始化(即创建并初始化配置的Bean)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
//调用方法
helloWorld.say();//Hello World

3. Bean configuration

3.1. Configuring beans through bean nodes in XML files

<!--class属性值为全类名,即Spring通过反射的方式创建Bean-->
<bean id="helloWorld" class="org.lin.stu.spring.HelloWorld">
    <property name="name" value="World"/>
</bean>

id (the name of the bean):

  • Must be unique within an IOC container
  • If the id is not specified, Spring will automatically generate it in the format: full class name#number (for example: org.lin.stu.spring.HelloWorld#0)

3.2. BeanFactory&ApplicationContext

BeanFactory is the basic implementation of the IOC container. ApplicationContext provides more advanced features and is a sub-interface of BeanFactory.

BeanFactory is the infrastructure of the Spring framework and is oriented to Spring itself, while ApplicationContext is oriented to developers who use the Spring framework. Almost all applications use ApplicationContext directly instead of the underlying BeanFactory.

3.3. ApplicationContext

  • The main implementation class of ApplicationContext:
    • ClassPathXmlApplicationContext: Load configuration files from the classpath
    • FileSystemXmlApplicationContext: Load configuration files from the file system
  • All singleton beans are created and initialized when the IOC container is initialized
  • WebApplicationContext is specially prepared for WEB applications

3.4. Obtaining beans by type

HelloWorld helloWorld = ctx.getBean(HelloWorld.class);

If there are multiple beans of the same type in the IOC container, NoUniqueBeanDefinitionException is thrown.

3.5. Dependency Injection

Spring supports 3 ways of dependency injection:

  • property injection
  • Constructor injection
  • Factory Method Injection (rarely used, not recommended)

3.5.1. Property injection

  • Attribute injection is to inject the attribute value of the bean or the dependent object through the set method
  • Attribute injection uses the <property> element, the name attribute value is a setter-style attribute name, and the value attribute or <value> child node specifies the attribute value
  • Property injection is the most commonly used injection method in practical applications

3.5.2. Constructor Injection

Inject Bean's property value or dependent object through the constructor

Car.java

package org.lin.stu.spring;

public class Car {

    private String brand;//品牌
    private Double price;
    private Integer maxSpeed;

    public Car() {
    }

    public Car(String brand, Double price) {
        this.brand = brand;
        this.price = price;
    }

    public Car(String brand, Integer maxSpeed) {
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }

    //getters and setters are omitted
}
<bean id="car1" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi"/>
    <constructor-arg value="300000"/>
</bean>

<bean id="car2" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi"/>
    <constructor-arg value="240"/>
</bean>

The above code is equivalent to:

<bean id="car1" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi" index="0"/>
    <constructor-arg value="300000" index="1"/>
</bean>

<bean id="car2" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi" index="0"/>
    <constructor-arg value="240" index="1"/>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car1 = (Car) ctx.getBean("car1");
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car1);//Car{brand='Audi', price=null, maxSpeed=300000}
System.out.println(car2);//Car{brand='Audi', price=null, maxSpeed=240}

Because 300000 and 240 can be converted to either Double or Integer, at this time, the order alone cannot achieve the purpose.

The above problem can be avoided by the type attribute:

<bean id="car1" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi"/>
    <constructor-arg value="300000" type="java.lang.Double"/>
</bean>

<bean id="car2" class="org.lin.stu.spring.Car">
    <constructor-arg value="Audi" index="0"/>
    <constructor-arg type="java.lang.Integer">
        <value>240</value>
    </constructor-arg >
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car1 = (Car) ctx.getBean("car1");
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car1);//Car{brand='Audi', price=300000.0, maxSpeed=null}
System.out.println(car2);//Car{brand='Audi', price=null, maxSpeed=240}

3.6. Literals

  • Values ​​that can be represented by strings (basic data types and their encapsulation types, String, etc.) can be injected through the <value> tag or value attribute
  • If the literal value contains special characters (such as '<' and other characters), you can use <![CDATA[]]> to wrap the literal value, but it can only be injected through the <value> tag, for example: <value><! [CDATA[<Audi>]]></value>

3.7. Referencing other beans

  • The beans that make up an application often need to cooperate with each other to complete the functionality of the application
  • In the bean's configuration file, you can specify the referenced bean for the bean's properties through the <ref> tag or ref attribute
  • You can also include a bean declaration in the <property> tag or <constructor-arg> tag, such a bean is called an internal bean
package org.lin.stu.spring;

public class Person {
    private String name;
    private Car car;

    //getters and setters are omitted
}
package org.lin.stu.spring;

public class Car {
    private String brand;
    private Double price;
    private Integer maxSpeed;

    //getters and setters are omitted
}
<bean id="car" class="org.lin.stu.spring.Car">
    <property name="brand" value="Audi"/>
    <property name="price" value="300000"/>
</bean>

<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Alan"/>
    <property name="car">
        <ref bean="car"/>
    </property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Alan', car=Car{brand='Audi', price=300000.0, maxSpeed=null}}

3.8. Internal Beans

  • When a bean is only used in a certain place, it can be declared as an internal bean, and the internal bean declaration is directly contained in the <property> or <constructor-arg> tag, without setting the id attribute
  • Internal beans cannot be used anywhere else
package org.lin.stu.spring;

public class Person {
    private String name;
    private Car car;

    //getters and setters are omitted
}
package org.lin.stu.spring;

public class Car {
    private String brand;
    private Double price;
    private Integer maxSpeed;

    //getters and setters are omitted
}
<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Alan"/>
    <property name="car">
        <bean class="org.lin.stu.spring.Car">
            <property name="brand" value="Audi"/>
            <property name="price" value="300000"/>
        </bean>
    </property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Alan', car=Car{brand='Audi', price=300000.0, maxSpeed=null}}

3.9. Null and Cascading Properties

  • You can use the <null/> tag to inject null values ​​into bean properties
  • Spring supports configuration of cascading properties
<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Alan"/>
    <!--级联属性赋值前需要先指定引用-->
    <property name="car" ref="car"/>
    <property name="car.brand" value="Ford"/>
</bean>

3.10. Collection properties

  • Collection properties can be configured using a set of built-in XML tags
  • Attributes of type java.util.List need to be configured using the <list> tag, and some elements are configured in the tag. These elements can be <value> elements (configure literal values), or <ref> elements (specify the parameters for other beans). reference), it can also be a <bean> element (to configure built-in beans), it can also be a <null/> element, or even other collections can be embedded
  • Arrays, like Lists, also use the <list> tag
  • The properties of type java.util.Set need to be configured using the <set> tag, the configuration method is the same as that of List
  • Attributes of type java.util.Map need to be configured using the <map> tag. Multiple <entry> tags can be used in the <map> tag. Each <entry> tag contains a key and a value, because the types of keys and values ​​are not restrictions, so feel free to use <value>, <ref>, <bean> or <null/> tags to specify values ​​for them, keys and values ​​can be specified through attributes, simple values ​​are specified through key and value attributes, and bean references are specified through key -ref and value-ref attribute specification
  • Properties of type java.util.Properties need to be configured using the <props> tag. Multiple <prop> tags can be used in the <props> tag. Each <prop> tag must specify a key attribute

3.10.1. List

package org.lin.stu.spring;

public class Car {
    private String brand;
    private Double price;
    private Integer maxSpeed;

    //getters and setters are omitted
}
package org.lin.stu.spring;

import java.util.List;

public class Person {
    private String name;
    private List<Car> cars;

    //getters and setters are omitted
}
<bean id="car1" class="org.lin.stu.spring.Car">
    <property name="brand" value="Audi"/>
    <property name="price" value="300000"/>
</bean>

<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Mike"/>
    <property name="cars">
        <list>
            <ref bean="car1"/>
        </list>
    </property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Mike', cars=[Car{brand='Audi', price=300000.0, maxSpeed=null}]}

3.10.2. Map

package org.lin.stu.spring;

public class Car {
    private String brand;
    private Double price;
    private Integer maxSpeed;

    //getters and setters are omitted
}
package org.lin.stu.spring;

import java.util.Map;

public class Person {
    private String name;
    private Map<String, Car> cars;

    //getters and setters are omitted
}
<bean id="car1" class="org.lin.stu.spring.Car">
    <property name="brand" value="Audi"/>
    <property name="price" value="300000"/>
</bean>

<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Mike"/>
    <property name="cars">
        <map>
            <entry key="A" value-ref="car1"/>
        </map>
    </property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Mike', cars={A=Car{brand='Audi', price=300000.0, maxSpeed=null}}}

3.10.3. Properties

package org.lin.stu.spring;

import java.util.Properties;

public class DataSource {
    private Properties properties;

    //getters and setters are omitted
}
<bean id="dataSource" class="org.lin.stu.spring.DataSource">
    <property name="properties">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123</prop>
            <prop key="url">jdbc:mysql///test</prop>
            <prop key="driverClass">com.mysql.jdbc.Driver</prop>
        </props>
    </property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
//DataSource{properties={password=123, driverClass=com.mysql.jdbc.Driver, url=jdbc:mysql///test, username=root}}

3.11. Configuring collections using the util scheme

  • The basic collection configuration cannot use it as an independent definition, so that other beans cannot be referenced and cannot be shared between different beans
  • Independent collections can be configured using the util schema
package org.lin.stu.spring;

public class Car {
    private String brand;
    private Double price;
    private Integer maxSpeed;

    //getters and setters are omitted
}
<bean id="car" class="org.lin.stu.spring.Car">
    <property name="brand" value="Audi"/>
    <property name="price" value="300000"/>
</bean>

<bean id="person" class="org.lin.stu.spring.Person">
    <property name="name" value="Mike"/>
    <property name="cars" ref="cars"/>
</bean>

<util:list id="cars">
    <ref bean="car"/>
</util:list>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Mike', cars=[Car{brand='Audi', price=300000.0, maxSpeed=null}]}

3.12. Using the p namespace

To simplify configuration, more and more XML files use attributes instead of sub-elements. Spring has introduced a new p namespace since 2.5, which can configure the properties of beans by means of attributes. After using the p namespace, the XML-based configuration will be further simplified.

3.13. Autowiring

The Spring IOC container can autowire beans, all you need to do is specify the autowired mode through the autowire attribute of <bean>.

  • byType (autowired according to type): If there are multiple beans with matching types in the IOC container, a NoUniqueBeanDefinitionException is thrown
  • byName (autowired by name): The name of the target bean must be the same as the setter-style property name
  • Constructor (automatic assembly according to the constructor): When there are multiple constructors in the class, this automatic assembly method will be very complicated and is not recommended.
package org.lin.stu.spring.autowire;

public class Person {
    private String name;
    private Address address;
    private Car car;

    //getters and setters are omitted
}
package org.lin.stu.spring.autowire;

public class Address {
    private String city;
    private String street;

    //getters and setters are omitted
}
package org.lin.stu.spring.autowire;

public class Car {
    private String brand;
    private Double price;

    //getters and setters are omitted
}

3.13.1. byName

<bean id="addr" class="org.lin.stu.spring.autowire.Address" p:city="ChengDu" p:street="ShengBangJie"/>
<bean id="car" class="org.lin.stu.spring.autowire.Car" p:brand="Audi" p:price="300000"/>
<bean id="person" class="org.lin.stu.spring.autowire.Person" p:address-ref="addr" p:name="Tom" autowire="byName"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("autowire.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Tom', address=Address{city='ChengDu', street='ShengBangJie'}, car=Car{brand='Audi', price=300000.0}}

3.13.2. byType

<bean id="addr" class="org.lin.stu.spring.autowire.Address" p:city="ChengDu" p:street="ShengBangJie"/>
<bean id="car" class="org.lin.stu.spring.autowire.Car" p:brand="Audi" p:price="300000"/>
<bean id="person" class="org.lin.stu.spring.autowire.Person" p:name="Tom" autowire="byType"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("autowire.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Tom', address=Address{city='ChengDu', street='ShengBangJie'}, car=Car{brand='Audi', price=300000.0}}

3.13.3. Disadvantages of Autowiring

  • Setting the autowire property in the bean configuration for autowiring will wire all properties of the bean
  • Either autowire by type, or autowire by name, not both
  • In general, autowiring is rarely used in actual projects, because clear configuration documentation is more convincing than the benefits of autowiring

3.14. Inheritance relationship between beans

  • Spring allows inheritance between beans, the inherited bean is called the parent bean, and the inherited bean is called the child bean
  • The child bean inherits the configuration of the parent bean, including attribute configuration
  • Child beans can also override configuration inherited from parent beans
  • The parent bean can be used as a configuration template or as a bean instance. If you only want to use the parent bean as a configuration template, you can set the abstract attribute to true, so that Spring will not instantiate this bean
  • Not all attributes of the <bean> element will be inherited, such as: autowire, abstract, etc.
  • You can also ignore the class attribute of the parent bean, let the child bean specify it by itself, and share the same attribute configuration, but at this time the bean must be an abstract bean
package org.lin.stu.spring.relation;

public class Address {
    private String city;
    private String street;

    //getters and setters are omitted
}
<bean id="address1" class="org.lin.stu.spring.relation.Address" p:city="ChengDu" p:street="YuLinLu"/>
<bean id="address2" p:street="BaiCaoLu" parent="address1"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("relation.xml");
Address address1 = (Address) ctx.getBean("address1");
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address1);//Address{city='ChengDu', street='YuLinLu'}
System.out.println(address2);//Address{city='ChengDu', street='BaiCaoLu'}

3.15. Dependencies between beans

Spring allows setting dependent beans through the depends-on attribute. The dependent beans will be assembled before this bean is instantiated. If there are no dependent beans in the container, a NoSuchBeanDefinitionException will be thrown.

3.16. Bean scope

In Spring, you can set the scope of a bean through the scope attribute of the <bean> tag. The values ​​are as follows:

  • singleton: the default value, the bean is created when the container is initialized, and it is only created once in the entire life cycle of the container
  • prototype: It is not created when the container is initialized, and a new instance is created and returned each time getBean(...) is called
  • request: a new instance is created for each HTTP request, this scope is only applicable to the WebApplicationContext environment
  • session: the same HttpSession shares an instance, this scope only applies to the WebApplicationContext environment
package org.lin.stu.spring.scope;

public class Car {
    private String brand;
    private Double price;

    //getters and setters are omitted
}
<bean id="car" class="org.lin.stu.spring.scope.Car" p:brand="Audi" p:price="300000"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("scope.xml");
Car car1 = (Car) ctx.getBean("car");
Car car2 = (Car) ctx.getBean("car");
System.out.println(car1 == car2);//true

3.17. Using an external properties file

  • Spring provides a BeanFactory post-processor of PropertyPlaceholderConfigurer, which allows users to move part of the Bean configuration (for example: file upload directory, data source information, etc.) to the property file, and use ${propName} in the Bean configuration file replace
  • Spring also allows the use of ${propName} in external property files to enable mutual references between properties

3.17.1. Before Spring 2.5

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:db.properties"/>
</bean>

3.17.2. After Spring 2.5

<context:property-placeholder location="classpath:db.properties"/>

Example:

package org.lin.stu.spring.properties;

public class DataSource {
    private String user;
    private String password;
    private String driverClass;
    private String jdbcUrl;

    //getters and setters are omitted
}

db.properties

user=root
password=${user}
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///test
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.lin.stu.spring.properties.DataSource">
    <property name="user" value="${user}"/>
    <property name="password" value="${password}"/>
    <property name="driverClass" value="${driverClass}"/>
    <property name="jdbcUrl" value="${jdbcUrl}"/>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("properties.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);//DataSource{user='root', password='root', driverClass='com.mysql.jdbc.Driver', jdbcUrl='jdbc:mysql:///test'}

3.18. SpEL (Spring Expression Language)

SpEL uses #{} as a delimiter, and the content in curly braces is considered SpEL. SpEL provides convenience for dynamic assignment of bean properties.

3.18.1. Literals

<!--整数-->
<property name="age" value="#{25}"/>
<!--小数-->
<property name="weight" value="#{120.5}"/>
<!--科学计数法-->
<property name="height" value="#{1e2}"/>
<!--String可以使用单引号或者双引号作为定界符号-->
<property name="truename" value="#{'唐僧'}"/>
<property name='nickname' value='#{"小唐"}'/>
<!--布尔值-->
<property name="isMale" value="#{false}"/>

3.18.2. Referencing other beans

<property name="car" value="#{car}"/>

3.18.3. Reference properties of other beans

<property name="city" value="#{address.city}"/>

3.18.4. Calling methods of other beans (supports chained calls)

<property name="info" value="#{user.toString()}"/>
<property name="upperCaseInfo" value="#{user.toString().toUpperCase()}"/>

 

//EVERYTHING

3.18.?. Example

package org.lin.stu.spring.spel;

public class Address {
    private String city;
    private String street;

    //getters and setters are omitted
}
package org.lin.stu.spring.spel;

public class Car {
    private String brand;
    private Double price;
    private Double tyrePerimeter;

    //getters and setters are omitted
}
package org.lin.stu.spring.spel;

public class Person {
    private String name;
    private Car car;
    private String city;
    //根据car的price确定,如果price>=300000,info为金领,否则为白领
    private String info;

    //getters and setters are omitted
}
<bean id="address" class="org.lin.stu.spring.spel.Address">
    <!--使用SpEL为属性赋字面值-->
    <property name="city" value="#{'ChengDu'}"/>
    <property name="street" value="BaiCaoLu"/>
</bean>

<bean id="car" class="org.lin.stu.spring.spel.Car">
    <property name="brand" value="Audi"/>
    <property name="price" value="300000"/>
    <!--使用SpEL访问类的静态属性(也可以调用类的静态方法)-->
    <property name="tyrePerimeter" value="#{T(java.lang.Math).PI * 80}"/>
</bean>

<bean id="person" class="org.lin.stu.spring.spel.Person">
    <property name="name" value="Tom"/>
    <!--使用SpEL引用其他的Bean-->
    <property name="car" value="#{car}"/>
    <!--使用SpEL引用其他Bean的属性-->
    <property name="city" value="#{address.city}"/>
    <property name="info" value="#{car.price >= 300000 ? '金领' : '白领'}"/>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("spel.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);//Person{name='Tom', car=Car{brand='Audi', price=300000.0, tyrePerimeter=251.32741228718345}, city='ChengDu', info='金领'}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324405618&siteId=291194637