[Spring from entry to actual combat tutorial] Chapter 2 Spring Configuration Bean

2. Configuration of Spring Bean

    Objects managed by the Spring IoC container are called beans, and beans are created based on information in the Spring configuration file. The so-called configuration bean is to tell Spring's IOC container the object to be managed.

2.1 Ways to configure beans

2.1.1 Traditional XML configuration method

Person.java:

public class Person {
    private String name;
    private int age;
    private double money;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", money=" + money +
                '}';
    }
}

applicationContext.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标签:让spring创建一个对象并放置在IOC容器内,一个bean标签就对应某个类的一个对象
    属性:
        id: 该bean对象的唯一标识符,bean的名称,不能重复的
        class: 需要创建对象的类型的全限定名,Spring通过反射机制创建该类的对象(要求:该类必须拥有无参构造方法)
    -->
    <bean id="person1" class="com.newcapec.bean.Person"/>
    <bean id="person2" class="com.newcapec.bean.Person">
</beans>

Attribute resolution:

  • id : The name of the bean must be unique in the IOC container. No matter whether the configuration file is split or annotations are used later, the id must not be repeated; if the id is not specified, Spring will automatically use the fully qualified class name of the class as the name of the bean;

  • class : the fully qualified name of the java class;

BeanTest.java:

public class BeanTest {

    @Test
    public void testBeanXML(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Person p1 = (Person) ac.getBean("person1");
        System.out.println(p1);

        Person p2 = (Person) ac.getBean("person2");
        System.out.println(p2);

        //测试p1和p2是不是指向同一个地址
        System.out.println(p1 == p2);//false,验证一个Bean对应一个对象

        Person p3 = (Person) ac.getBean("person1");
        System.out.println(p1 == p3);//true
    }
}

2.1.2 Configuration based on Java annotations

    Please pay attention to the following chapters.

2.1.3 Class-based Java Config

    Please pay attention to the following chapters.

2.2 Ways to instantiate beans

2.2.1 Instantiate Bean through the constructor

    The Spring IoC container can use the default empty constructor or the parameterized constructor to instantiate the Bean object through the reflection mechanism.

2.2.2 Instantiate beans through factories

    Please pay attention to the following chapters.

2.2.3 FactoryBean Instantiation Bean

    Please pay attention to the following chapters.

2.3 Spring container

    The IoC idea is implemented based on the IoC container, and the bottom layer of the IoC container is actually a Bean factory. The Spring framework provides us with two different types of IoC containers, which are BeanFactory and ApplicationContext.

2.3.1 BeanFactory

    BeanFactory is the basic implementation of IoC container and also the simplest IoC container provided by Spring. It provides the most basic functions of IoC container and is defined by org.springframework.beans.factory.BeanFactory interface.

    BeanFactory adopts a lazy-load mechanism. When the container loads the configuration file, the Java object will not be created immediately, but will only be created when the object is acquired (used) in the program.
    
    Note: BeanFactory is an internal interface used by Spring, and it is usually not provided for developers to use. 

2.3.2 ApplicationContext

    ApplicationContext is a sub-interface of BeanFactory interface, which is an extension of BeanFactory. ApplicationContext adds many enterprise-level functions on the basis of BeanFactory, such as AOP (aspect-oriented programming), internationalization, transaction support, etc.

2.3.3 Main implementation classes of ApplicationContext

  • ClassPathXmlApplicationContext: Load configuration files from the class path;

  • FileSystemXmlApplicationContext: load configuration files from the file system;

  • WebApplicationContext: specially prepared for WEB applications, it allows initialization from a path relative to the WEB root directory;

2.3.4 Get the Bean from the container

  • The getBean(String name) method obtains the Bean object from the container through the Bean id;

  • The getBean(Class requiredType) method obtains the Bean object from the container through the Class type of the Bean;

  • The getBean(String name, Class requiredType) method obtains the Bean object from the container through the Bean's id and Class type;

Note: When there are multiple objects of this type stored in the IOC container, the Bean object cannot be obtained through the Class type.

BeanTest.java

public class BeanTest {
    @Test
    public void testGetBean() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //1.参数为字符串类型
        Person p1 = (Person) ac.getBean("person1");
        System.out.println(p1);

        //2.参数为Class类型,缺点:当IOC容器中存在多个此类型对象时,抛出异常
        Person person = ac.getBean(Person.class);
        System.out.println(person);

        //3.参数为字符串类型+Class类型
        Person p2 = ac.getBean("person2", Person.class);
        System.out.println(p2);
    }
}

2.4 Dependency Injection

2.4.1 Property-based injection

    We can inject the attribute value into the Bean's property through the Bean's setter method.
    
    In the process of instantiating beans in Spring, the IoC container will first call the default constructor (no-argument constructor) to instantiate the Bean (Java object), and then call the bean's setXxx() method through the Java reflection mechanism to set the property value Inject into the bean.
    
    Use setter injection for property injection, the general steps are as follows:
        1. Provide a default no-argument constructor in the Bean (it can be omitted if there are no other parameter constructors), and provide all properties that need to be injected. A setXxx() method;
        2. In the Spring XML configuration file, use <beans> and its child element <bean> to define the bean;
        3. Use the <property> element in the <bean> element to assign values ​​to each property , use the name attribute to specify the property name of the Bean, and the value attribute or <value> subtag to specify the property value.
        
    Property injection is the most commonly used injection method in practical applications.

applicationContext.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">

    <!-- 通过setter方法注入属性值 -->
    <bean id="person" class="com.newcapec.bean.Person">
        <!--
        property标签:表示通过属性的set方法为属性赋值,也叫做依赖注入
        属性:
        	name: 对象中的属性名称
        	value: 属性值
        -->
        <property name="name" value="张三"/>
        <property name="age" value="20"/>
        <property name="money">
            <value>3600.5</value>
        </property>
    </bean>
</beans>
public class DiTest {

    @Test
    public void testSet() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Person person = ac.getBean("person", Person.class);

        System.out.println(person);
    }
}

2.4.2 Constructor-based method injection

    We can implement the property injection of the Bean through the parameterized constructor of the Bean.
    
    The general steps to implement attribute injection using constructors are as follows:
        1. Add a parameterized constructor to the Bean, and each parameter in the constructor represents an attribute that needs to be injected;
        
        2. In the Spring XML configuration file, pass <beans> And its child element <bean> defines the Bean;

        3. Use the <constructor-arg> element in the <bean> element to assign values ​​to the attributes in the constructor. As many parameters as there are in the Bean constructor, you need to use as many <constructor-arg> elements.

Car.java:

public class Car {
    private String name;
    private String type;
    private double price;
    private int doors;

    public Car(String name, String type, double price, int doors) {
        this.name = name;
        this.type = type;
        this.price = price;
        this.doors = doors;
    }

    public Car(String name, String type, int doors) {
        this.name = name;
        this.type = type;
        this.doors = doors;
    }

    public Car(String name, String type, double price) {
        this.name = name;
        this.type = type;
        this.price = price;
    }

    public Car(String n, String t) {
        this.name = n;
        this.type = t;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", price=" + price +
                ", doors=" + doors +
                '}';
    }
}

applicationContext.xml:

Note: If there are multiple construction methods in this class, select the construction method precisely by index, type or name.

<?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="car1" class="com.newcapec.bean.Car">
        <!--
        constructor-arg : 表示创建该类型的对象时,使用的构造方法的参数
        属性:
            value : 构造方法的参数值
            index : 构造方法参数的索引
            type : 构造方法参数的类型
            name : 构造方法参数的名称
        -->
        <constructor-arg value="宝马"/>
        <constructor-arg value="轿车"/>
        <constructor-arg value="360000"/>
        <constructor-arg value="4"/>
    </bean>
</beans>
  • Match constructor parameters by index

<bean id="car2" class="com.newcapec.bean.Car">
    <constructor-arg value="越野" index="1"/>
    <constructor-arg value="奔驰" index="0"/>
    <constructor-arg value="4" index="3"/>
    <constructor-arg value="560000" index="2"/>
</bean>
  • Match constructor parameters by type

<bean id="car3" class="com.newcapec.bean.Car">
    <constructor-arg value="大众" type="java.lang.String"/>
    <constructor-arg value="商务车" type="java.lang.String"/>
    <constructor-arg value="290000" type="double"/>
</bean>
  • Match constructor parameters by parameter name

<bean id="car4" class="com.newcapec.bean.Car">
    <constructor-arg value="电动车" name="t"/>
    <constructor-arg value="特斯拉" name="n"/>
</bean>

test:

public class DiTest {
    @Test
    public void testConstructor() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Car car1 = ac.getBean("car1", Car.class);
        System.out.println(car1);

        Car car2 = ac.getBean("car2", Car.class);
        System.out.println(car2);

        Car car3 = ac.getBean("car3", Car.class);
        System.out.println(car3);

        Car car4 = ac.getBean("car4", Car.class);
        System.out.println(car4);
    }
}

2.5 Injecting attribute values

2.5.1 Literal values

  • A value that can be represented by a string can <value>be injected through the label or value attribute;

  • Literal value injection can be used for basic data types, wrapper types, String and other types. Spring will automatically convert the string to the corresponding data type;

  • If the literal value contains special characters, you can use <![CDATA[]]>to wrap the literal value;

Person.java:

public class Person {
    private String name;
    private int age;
    private double money;
    private Date birthday;
    private boolean gender;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public boolean isGender() {
        return gender;
    }

    public void setGender(boolean gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", money=" + money +
                ", birthday=" + birthday +
                ", gender=" + gender +
                '}';
    }
}

applicationContext.xml:

<!--注入属性值:字面值-->
<bean id="per" class="com.newcapec.bean.Person">
    <property name="name" value="李四"/>
    <!--特殊值写法-->
    <!--<property name="name">
            <value><![CDATA[1<2]]></value>
        </property>-->
    <property name="age" value="20"/>
    <property name="money" value="3000.8"/>
    <!--对于日期值,如果写其他格式,不识别-->
    <property name="birthday" value="1998/05/12"/>
    <property name="gender" value="true"/>
</bean>

test:

@Test
public void testValue() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    Person per = ac.getBean("per", Person.class);

    System.out.println(per);
}

2.5.2 Referencing other beans

    Beans that make up an application often need to cooperate with each other to complete the functions of the application. To enable beans to access each other, you must specify a reference to the bean in the bean configuration file.

Customer.java:

public class Customer {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Order.java:

public class Order {
    private String orderNum;
    private double price;
    /**
     * 自定义类型的属性
     */
    private Customer customer;

    public Order() {
    }

    public Order(String orderNum, double price, Customer customer) {
        this.orderNum = orderNum;
        this.price = price;
        this.customer = customer;
    }

    public String getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(String orderNum) {
        this.orderNum = orderNum;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderNum='" + orderNum + '\'' +
                ", price=" + price +
                ", customer=" + customer +
                '}';
    }
}
  • 2.5.2.1 Inner Bean method

    We will define a bean inside a <property> or <constructor-arg> element of a <bean> element as an "inner bean".

1. The setter method injects internal beans:

    We can inject inner beans through setters. At this point, we only need to use the <bean> element again to define the internal bean in the <property> element under the <bean> tag, the format is as follows.

<?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-3.0.xsd">

    <bean id="outerBean" class="……">
        <property name="……" >
            <!-- 定义内部 Bean -->
            <bean class="……">
                <property name="……" value="……" ></property>
                ……
            </bean>
        </property>
    </bean>
</beans>

    Note: Internal beans are all anonymous, no need to specify id and name. Even if it is specified, the IoC container will not use it as an identifier to distinguish the Bean, but will ignore the Scope tag of the Bean. So inner beans are almost always anonymous and always created along with outer beans. An inner bean cannot be injected into any other bean other than the bean it resides in.

<bean id="order1" class="com.newcapec.bean.Order">
    <property name="orderNum" value="20220413001"/>
    <property name="price" value="998"/>
    <!--setter 方式注入内部 Bean-->
    <property name="customer">
        <bean class="com.newcapec.bean.Customer">
            <property name="username" value="tom"/>
            <property name="password" value="123456"/>
        </bean>
    </property>
</bean>

2. Constructor way to inject internal Bean:

    We can inject the inner bean through the constructor. At this point, we only need to use the <bean> element again to define the internal bean in the <constructor-arg> element under the <bean> tag, and the format is as follows.

<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-3.0.xsd">

    <bean id="……" class="……">
        <constructor-arg name="……">
            <!--内部 Bean-->
            <bean class="……">
                <constructor-arg name="……" value="……"></constructor-arg>
                ……
            </bean>
        </constructor-arg>
    </bean>
</beans>

applicationContext.xml:

<bean id="order2" class="com.newcapec.bean.Order">
    <constructor-arg name="orderNum" value="20220413002"/>
    <constructor-arg name="price" value="799"/>
    <!--构造函数方式注入内部 Bean-->
    <constructor-arg name="customer">
        <bean class="com.newcapec.bean.Customer">
            <property name="username" value="jack"/>
            <property name="password" value="123456"/>
        </bean>
    </constructor-arg>
</bean>
  • 2.5.2.2 ref attribute reference method

    The ref attribute will look up the specified bean from the IOC container according to the name, and then assign the value by reference.

1. <property>The ref attribute in the tag:

<bean id="customer3" class="com.newcapec.bean.Customer">
    <property name="username" value="jerry"/>
    <property name="password" value="123456"/>
</bean>
<bean id="order3" class="com.newcapec.bean.Order">
    <property name="orderNum" value="20220413003"/>
    <property name="price" value="1299"/>
    <!-- 通过ref属性来注入属性值:其中ref属性的值为其他bean的id-->
    <property name="customer" ref="customer3"/>
</bean>

2. Sub-tags <property>in tags :<ref>

<bean id="customer4" class="com.newcapec.bean.Customer">
    <property name="username" value="Spike"/>
    <property name="password" value="123456"/>
</bean>
<bean id="order4" class="com.newcapec.bean.Order">
    <property name="orderNum" value="20220413004"/>
    <property name="price" value="698"/>
    <!-- 通过ref子标签来注入其他的bean对象-->
    <property name="customer">
        <ref bean="customer4"/>
    </property>
</bean>

test:

@Test
public void testRef() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    Order order1 = ac.getBean("order1", Order.class);
    System.out.println(order1);

    Order order2 = ac.getBean("order2", Order.class);
    System.out.println(order2);

    Order order3 = ac.getBean("order3", Order.class);
    System.out.println(order3);

    Order order4 = ac.getBean("order4", Order.class);
    System.out.println(order4);
}

2.5.3 Collection properties

    We can also use the following elements in the <property> element under the Bean tag to configure properties and parameters of Java collection types, such as List, Set, Map, and Properties.

Label illustrate
<list> Used to inject values ​​of type list, allowing repetition.
<set> It is used to inject the value of set type, duplication is not allowed.
<map> It is used to inject key-value collection, where both key and value can be of any type.
<props> Used to inject key-value collections, where key and value are both string types.

    Note: For values ​​of common types in the collection, they can be injected directly through the value subtag or the value attribute. For values ​​of custom types in the collection, they need to be injected through ref tags or internal beans.

Course.java:

public class Course {
    private int id;
    private String cname;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", cname='" + cname + '\'' +
                '}';
    }
}

Student.java:

public class Student {
    private int id;
    private String name;
    private List<Course> courseList;
    private Integer[] ids;
    private Set<String> stringSet;
    private Map<String, Course> courseMap;
    private Properties props;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<Course> getCourseList() {
        return courseList;
    }

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

    public Integer[] getIds() {
        return ids;
    }

    public void setIds(Integer[] ids) {
        this.ids = ids;
    }

    public Set<String> getStringSet() {
        return stringSet;
    }

    public void setStringSet(Set<String> stringSet) {
        this.stringSet = stringSet;
    }

    public Map<String, Course> getCourseMap() {
        return courseMap;
    }

    public void setCourseMap(Map<String, Course> courseMap) {
        this.courseMap = courseMap;
    }

    public Properties getProps() {
        return props;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", courseList=" + courseList +
                ", ids=" + Arrays.toString(ids) +
                ", stringSet=" + stringSet +
                ", courseMap=" + courseMap +
                ", props=" + props +
                '}';
    }
}
  • 2.5.3.1 List collection

    To configure properties of the java.util.List type, you need to specify the <list> tag, which contains some elements. These tags can specify simple constant values ​​via <value> and references to other beans via <ref>.

<bean id="course1" class="com.newcapec.bean.Course">
    <property name="id" value="10"/>
    <property name="cname" value="Java语言"/>
</bean>
<bean id="course2" class="com.newcapec.bean.Course">
    <property name="id" value="20"/>
    <property name="cname" value="Oracle数据库"/>
</bean>
<bean id="course3" class="com.newcapec.bean.Course">
    <property name="id" value="30"/>
    <property name="cname" value="Spring框架"/>
</bean>

<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <property name="courseList">
        <list>
            <ref bean="course1"/>
            <ref bean="course2"/>
            <ref bean="course3"/>
            <!--内部bean-->
            <bean class="com.newcapec.bean.Course">
                <property name="id" value="40"/>
                <property name="cname" value="Mybatis框架"/>
            </bean>
        </list>
    </property>
</bean>
@Test
public void testCollection() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    Student student = ac.getBean("student", Student.class);
    System.out.println(student);
}
  • 2.5.3.2 Object[] array

    To configure properties of an array type, use the `<array>` tag.

<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <!-- 数组:array子标签-->
    <property name="ids">
        <array>
            <value>10</value>
            <value>20</value>
            <value>30</value>
            <value>40</value>
        </array>
    </property>
</bean>
  • 2.5.3.3 Set collection

    To configure properties of type java.util.Set, use the `<set>` tag.

<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <!-- set集合:set子标签-->
    <property name="stringSet">
        <set>
            <value>hello</value>
            <value>goodbye</value>
            <value>how are you</value>
        </set>
    </property>
</bean>
  • 2.5.3.4 Map collection

    java.util.Map is defined by the `<map>` tag, and multiple `<entry>` can be used as sub-tags in the `<map>` tag. Each `<entry>` contains a key and a value. Simple types are defined using key and value attributes, and Bean references are defined through key-ref and value-ref attributes.

<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <!-- map集合:map子标签-->
    <property name="courseMap">
        <map>
            <!--
            entry标签:表示Map集合中的一组键值对
            key: 表示Map集合中的键为字面值
            key-ref: 表示Map集合中的键为自定义类型
            value: 表示Map集合中的值为字面值
            value-ref: 表示Map集合中的值为自定义类型
            -->
            <entry key="one" value-ref="course3"/>
            <entry key="two" value-ref="course1"/>
        </map>
    </property>
</bean>
  • 2.5.3.5 Properties

    Use `<props>` to define java.util.Properties. This tag uses multiple `<prop>` as sub-tags. Each `<prop>` tag must define the key attribute.

<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <!-- Properties类型的属性 -->
    <property name="props">
        <props>
            <!-- prop标签,表示Properties集合中的一个键值对,key属性对应的键,prop开始标签与结束标签之后的区域填写值-->
            <prop key="hello">你好</prop>
            <prop key="goodbye">再见</prop>
        </props>
    </property>
</bean>
  • 2.5.3.6 Singleton Collections

    Singleton collection: used by multiple beans. Use the `<util>` tag to define the collection outside the bean.

    Note: Requires importing the util namespace and tag spec.

xmlns:util="http://www.springframework.org/schema/util"

http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
<bean id="student" class="com.newcapec.bean.Student">
    <property name="id" value="1001"/>
    <property name="name" value="小明"/>
    <!-- 引入单例集合 -->
    <property name="courseList" ref="myList"></property>
</bean>

<!-- 外部集合:多个集合属性可同时引用 -->
<util:list id="myList">
    <ref bean="course1"/>
    <ref bean="course2"/>
    <ref bean="course3"/>
    <bean class="com.newcapec.bean.Course">
        <property name="id" value="40"/>
        <property name="cname" value="MySQL数据库"/>
    </bean>
</util:list>

2.5.4 Short Namespace Injection

    When we perform property injection through the constructor or setter method, we usually implement it by nesting <property> and <constructor-arg> elements in the <bean> element. Although this method has a clear structure, it is more cumbersome to write.

    The Spring framework provides two short namespaces, which can simplify the XML configuration of Spring, as shown in the following table.

short namespace Simplified XML configuration illustrate
p namespace <bean><property>elements nested within elements It is a shortcut implementation of setter property injection
c namespace <bean><constructor>elements nested within elements Is a shortcut implementation of constructor property injection

Dept.java:

public class Dept {
    private int deptno;
    private String dname;
    private String loc;

    public Dept() {
    }

    public Dept(int deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }

    public int getDeptno() {
        return deptno;
    }

    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }
}

Emp.java:

public class Emp {
    private int empno;
    private String ename;
    /**
     * 关系属性
     */
    private Dept dept;

    public Emp() {
    }

    public Emp(int empno, String ename, Dept dept) {
        this.empno = empno;
        this.ename = ename;
        this.dept = dept;
    }

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", dept=" + dept +
                '}';
    }
}
  • 2.5.4.1p Namespace Injection

    The p namespace is a shortcut implementation of setter-style property injection. Through it, we can implement setter property injection in the form of bean properties instead of using nested <property> elements to achieve the purpose of simplifying Spring's XML configuration.

    First we need to import the following XML constraints in the <beans> element of the configuration file.

xmlns:p="http://www.springframework.org/schema/p"

After importing XML constraints, we can implement attribute injection in the following form:

<bean id="Bean 唯一标志符" class="包名+类名" p:普通属性="普通属性值" p:对象属性-ref="对象的引用">

When using the p namespace to inject dependencies, you must pay attention to the following three points:

  • There must be a setter method in the Java class;

  • There must be a parameterless constructor in a Java class (the class does not contain any parameterized constructor, the parameterless constructor exists by default);

  • Before using the p namespace to implement attribute injection, the XML constraints of the p namespace must be imported into <beans>the elements .

applicationContext.xml:

<!-- 通过p命名空间的方式,来简化依赖注入 -->
<bean id="dept" class="com.newcapec.bean.Dept" p:deptno="10" p:dname="研发部" p:loc="郑州"/>

<bean id="emp" class="com.newcapec.bean.Emp" p:empno="8000" p:ename="张三" p:dept-ref="dept"/>

test:

@Test
public void testPNameSpace() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    Emp emp = ac.getBean("emp", Emp.class);
    System.out.println(emp);
}
  • 2.5.4.2 c namespace injection

    The c namespace is a shortcut for constructor injection. Through it, we can realize the attribute injection of the constructor method in the form of the <bean> attribute, instead of using the nested <constructor-arg> element, in order to achieve the purpose of simplifying the XML configuration of Spring.

    First we need to import the following XML constraints in the <beans> element of the configuration file.

xmlns:c="http://www.springframework.org/schema/c"

After importing XML constraints, we can implement attribute injection in the following form:

<bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">

When using the c namespace to inject dependencies, you must pay attention to the following 2 points:

  • The Java class must contain the corresponding parameterized constructor;

  • Before using the c namespace to implement attribute injection, the XML constraints of the c namespace must be imported into <beans>the elements .

applicationContext.xml:

<!-- 通过c命名空间的方式,来简化依赖注入 -->
<bean id="department" class="com.newcapec.bean.Dept" c:deptno="20" c:dname="产品部" c:loc="杭州"/>

<bean id="employee" class="com.newcapec.bean.Emp" c:empno="7369" c:ename="李四" c:dept-ref="department"/>

test:

@Test
public void testCNameSpace() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    Emp emp = ac.getBean("employee", Emp.class);
    System.out.println(emp);
}

2.5.5 autowire automatic assembly

    We call Spring's behavior of establishing dependencies between Beans and Beans "wiring".

    Although Spring's IOC container is powerful, it is just an empty shell, and it cannot complete the assembly work by itself. We need to take the initiative to put the Bean in and tell it the dependencies between the Bean and the Bean, so that it can complete the assembly work according to our requirements.

    In the previous studies, we manually maintained the dependency relationship between Bean and Bean through the ref attribute in <constructor-arg> and <property> in XML configuration.
    
    For applications that contain only a small number of beans, this approach is sufficient for our needs. But with the continuous development of the application, more and more beans will be included in the container, and the dependencies between beans will become more and more complicated, which makes the XML configuration we write more and more complicated and more and more complex. more cumbersome.

    We know that an overly complex XML configuration is not only poor in readability, but also extremely error-prone when written, which seriously reduces the development efficiency of developers. In order to solve this problem, the Spring framework also provides us with the "autowiring" function.
    
    Spring's automatic assembly function allows the Spring container to find the beans it depends on from the application context (ApplicationContext container) for the specified bean according to certain rules (automatic assembly rules, there are five types), and automatically establish the relationship between the beans. dependencies. And this process is done without using any <constructor-arg> and <property> element ref attributes at all.

    Spring's automatic assembly function can effectively simplify the XML configuration of Spring applications, so when there are a lot of configurations, automatic assembly can be used to reduce the workload.

    The Spring framework does not support automatic assembly by default. If you want to use automatic assembly, you need to set the autowire attribute of the <bean> element in the Spring XML configuration file.

Spring provides a total of 5 automatic assembly rules, which correspond to the 5 values ​​of the autowire attribute, as shown in the following table:

attribute value illustrate
byName Autowire by name. Spring will look in the context ApplicationContext (IoC container) of the entire application according to the name of the object attribute in the Java class. If the id or name attribute value of a Bean is the same as the name of this object attribute, then get this Bean and establish an association relationship with the current Java class Bean.
byType Autowire by type. Spring will look in the context ApplicationContext (IoC container) of the entire application according to the type of the object property in the Java class. If the class attribute value of a Bean matches the type of the object attribute, the Bean is acquired and associated with the Bean of the current Java class.
constructor Similar to the byType pattern, except that it is applied to constructor parameters (dependencies), and an exception will be thrown if no bean of the same type as the constructor parameter is found in the container. In fact, according to the data type of the constructor parameter, the automatic assembly of the byType mode is performed.
default Indicates that the automatic assembly rule (default-autowire) <beans>set .
no The default value means that no automatic assembly is used, and the dependencies of the Bean must <constructor-arg>be <property>defined through the ref attributes of the and elements.
  • 2.5.5.1 Do not use autowire (autowire="no")

    autowire="no" means not to use automatic assembly. At this time, we must maintain the dependency relationship of the Bean through the <constructor-arg> of the <bean> element and the ref attribute of the <property> element.

  • 2.5.5.2 Autowire by name (autowire="byName")

    `autowire="byName"` means autowire by attribute name, the id or name of the Bean in the XML file must be the same as the attribute name in the class.
    
    Note: If the id or name of the Bean must match the attribute name in the class, it will be automatically assembled, if not, it will be the default value.

<!-- 自动装配 -->
<bean id="dept" class="com.newcapec.bean.Dept" p:deptno="10" p:dname="研发部" p:loc="郑州"/>
<bean id="department" class="com.newcapec.bean.Dept" c:deptno="20" c:dname="产品部" c:loc="杭州"/>

<bean id="emp" class="com.newcapec.bean.Emp" p:empno="7689" p:ename="王武" autowire="byName"/>
  • 2.5.5.3 Autowire by type (autowire="byType")

    `autowire="byType"` means autowire according to the data type of the object attribute in the class. Even if the id or name of the Bean in the XML file is different from the attribute name in the class, as long as the value of the class attribute of the Bean is the same type as the object attribute in the class, autowiring can be completed.
    
    Note: If multiple beans of the same type exist at the same time, the injection fails and an exception is thrown.

<!-- 自动装配 -->
<bean id="dept" class="com.newcapec.bean.Dept" p:deptno="10" p:dname="研发部" p:loc="郑州"/>
<bean id="department" class="com.newcapec.bean.Dept" c:deptno="20" c:dname="产品部" c:loc="杭州"/>

<bean id="emp" class="com.newcapec.bean.Emp" p:empno="7689" p:ename="马六" autowire="byType"/>
  • 2.5.5.4 Constructor autowiring (autowire="constructor")

    autowire="constructor" means to perform automatic assembly according to the constructor in the Java class.
    
    Rarely used and no longer demonstrated.

  • 2.5.5.5 Default autowiring mode (autowire="default")

    By default, the automatic assembly rule (default-autowire) set by the upper-level tag <beans> is used for assembly, and the configuration content in Beans.xml is as follows. 

<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-3.0.xsd" 
       default-autowire="byName">
    
    <!-- 自动装配 -->
    <bean id="dept" class="com.newcapec.bean.Dept" p:deptno="10" p:dname="研发部" p:loc="郑州"/>
    <bean id="department" class="com.newcapec.bean.Dept" c:deptno="20" c:dname="产品部" c:loc="杭州"/>

    <bean id="emp" class="com.newcapec.bean.Emp" p:empno="7689" p:ename="马六" autowire="default"/>
</beans>

Disadvantages of Bean autowiring in XML configuration:

  • Setting the autowire attribute in the bean configuration file for autowiring will wire all the properties of the bean. However, the autowire attribute is not flexible enough if you only want to assemble individual attributes;

  • autowire attributes are either autowired by type or by name, not both;

  • Under normal circumstances, the automatic assembly function is rarely used in actual projects, because compared with the benefits brought by the automatic assembly function, clear and clear configuration documents are more convincing;

2.6 Using external properties files

Add namespace and label specifications:

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

db.properties:

# Mysql相关配置
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false
jdbc.mysql.username=root
jdbc.mysql.password=root

Introduce an external properties file:

<!-- 读取外部的资源文件-->
<context:property-placeholder location="classpath:db.properties"/>

MyDataSource.java:

public class MyDataSource {
    private String driver;
    private String url;
    private String username;
    private String password;

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Access data in properties files via expressions:

<bean id="myDataSource" class="com.newcapec.bean.MyDataSource">
    <property name="driver" value="${jdbc.mysql.driver}"/>
    <property name="url" value="${jdbc.mysql.url}"/>
    <property name="username" value="${jdbc.mysql.username}"/>
    <property name="password" value="${jdbc.mysql.password}"/>
</bean>

test:

public class ReadPropertiesTest {

    @Test
    public void test() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        MyDataSource myDataSource = ac.getBean("myDataSource", MyDataSource.class);
        System.out.println(myDataSource);
    }
}

2.7 Bean scope

    By default, all Spring Beans are singletons, which means that there is only one Bean instance in the entire Spring application.

    We can add the scope attribute to the <bean> element to configure the scope of the Spring Bean. For example, if you need a new Bean instance every time you get a Bean, you should define the scope attribute of the Bean as prototype. If Spring needs to return the same Bean instance every time, you should define the scope attribute of the Bean as singleton.

    Spring 5 provides a total of 6 scopes, as shown in the following table.

Scope of action describe
singleton Default value, singleton mode . Indicates that the IOC container creates an instance of the bean when it is initialized, and only one instance of the bean is created in the entire life cycle of the container.
prototype The prototype mode means that the IOC container does not create an instance of the bean when it is initialized, but creates a new instance of the bean each time it is used.
request Each HTTP request, the container will create a Bean instance. This scope is only valid within the current HTTP Request.
session The same HTTP Session shares a Bean instance, and different Sessions use different Bean instances. This scope is only valid within the current HTTP Session.
application The same Web application shares a Bean instance, and this scope is valid within the current ServletContext. Similar to singleton, but singleton means that there is only one Bean instance in each IoC container, and there may be multiple IoC containers in a web application, but a web application will only have one ServletContext, and it can also be said that application is the bean instance in a web application. The real singleton pattern.
websocket The scope of websocket is WebSocket, which is valid in the entire WebSocket.

    Note: In the above 6 bean scopes, except singleton and prototype can be used directly in conventional Spring IoC containers (such as ClassPathXmlApplicationContext), the rest can only be used in Web-based ApplicationContext implementations (such as XmlWebApplicationContext) , otherwise an IllegalStateException will be thrown.
    
    In this section, we will only explain in detail the two bean scopes of singleton and prototype. As for other bean scopes, we will introduce them in subsequent courses.

Book.java:

public class Book {
    private int id;
    private String name;
    private double price;
    private String author;

    public Book(){
        System.out.println("Book对象被创建....");
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", author='" + author + '\'' +
                '}';
    }
}

2.7.1 singleton

    singleton is the default scope of the Spring container. When the scope of the bean is singleton, there will only be one shared bean instance in the Spring IoC container. The Bean instance will be stored in the cache, and all requests and references to the Bean will return the object instance in the cache as long as the id matches the Bean definition.

    If the scope of a Bean definition is singleton, then the Bean is called a singleton bean. In the Spring IoC container, singleton bean is the default way to create beans, which can better reuse objects and save the cost of repeatedly creating objects.

    In the Spring configuration file, you can use the scope attribute of the <bean> element to define the scope of the Bean as a singleton. The configuration method is as follows:

applicationContext.xml:

<!-- singleton -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记"
      p:price="98.5" p:author="吴承恩" scope="singleton"/>

2.7.2 prototype

    If the scope of a Bean definition is prototype, then the Bean is called a prototype bean. For prototype beans, the Spring container will create a new Bean instance each time the Bean is requested.
    
    In a sense, the Spring IoC container is equivalent to Java's new operator for prototype beans. It is only responsible for the creation of the Bean, and the subsequent life cycle management is done by the client code.
    
    In the Spring configuration file, you can use the scope attribute of the <bean> element to define the scope of the Bean as prototype, and the configuration method is as follows:

<!-- prototype -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记"
      p:price="98.5" p:author="吴承恩" scope="prototype"/>

test:

public class ScopeTest {
    @Test
    public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("------------分割线--------------");

        Book book1 = ac.getBean("book",Book.class);
        System.out.println(book1);
        Book book2 = ac.getBean("book",Book.class);
        System.out.println(book2);

        System.out.println(book1 == book2);
    }
}

2.8 Bean life cycle

    In traditional Java applications, the life cycle of a bean is very simple. After the bean is instantiated using the Java keyword new, the bean can be used. Once the Bean is not used for a long time, Java automatically performs garbage collection.

    In contrast, the life cycle of beans in Spring is more complicated. The Spring IOC container can manage the life cycle of beans. Spring allows custom tasks to be performed at specific points in the life cycle of beans, which can be roughly divided into the following five stages: 1. Bean life
        cycle Instantiation
        2. Bean attribute assignment
        3. Bean initialization
        4. Bean use
        5. Bean destruction
        
    Spring selects the Bean management method according to the scope
        of the Bean. For the Bean in the singleton scope, the Spring IoC container can accurately Control when the Bean is created, when it is initialized, and when it is destroyed;
        for the Bean of the prototype scope, the Spring IoC container is only responsible for creating it, and then handing over the Bean instance to the client code for management, the Spring IoC container will Its lifetime is no longer tracked.

2.8.1 Spring life cycle process

    The complete life cycle of Spring Bean starts from the creation of the Spring IoC container until the final Spring IoC container destroys the bean. The specific process is shown in the figure below.

The entire execution process of the Bean life cycle is described as follows:

  1. Spring starts, finds and loads the Bean that needs to be managed by Spring, and instantiates the Bean.

  2. Perform property injection on the Bean.

  3. If the Bean implements the BeanNameAware interface, Spring calls the Bean's setBeanName() method to pass in the current Bean's id value.

  4. If the Bean implements the BeanFactoryAware interface, Spring calls the setBeanFactory() method passing in a reference to the current factory instance.

  5. If the Bean implements the ApplicationContextAware interface, Spring calls the setApplicationContext() method to pass in a reference to the current ApplicationContext instance.

  6. If the Bean implements the BeanPostProcessor interface, Spring calls the interface's pre-initialization method postProcessBeforeInitialzation() to process the Bean. This is very important here, and Spring's AOP is implemented using it.

  7. If the bean implements the InitializingBean interface, Spring will call the afterPropertiesSet() method.

  8. If an initialization method is specified via the init-method attribute in the configuration file, the initialization method is called.

  9. If BeanPostProcessor is associated with the Bean, Spring will call the interface's initialization method postProcessAfterInitialization(). At this point, the Bean is ready to be used by the application system.

  10. If the scope of the bean is specified as singleton <bean>in , put the bean into the buffer pool of Spring IoC to trigger Spring's lifecycle management of the bean; if <bean>the scope of the bean is specified as prototype in , then The bean is handed over to the caller, and the caller manages the life cycle of the bean, and Spring no longer manages the bean.

  11. If the Bean implements the DisposableBean interface, Spring will call the destroy() method to destroy the Bean; if the Bean's destruction method is specified through the destroy-method attribute in the configuration file, Spring will call this method to destroy the Bean.

2.8.2 Custom Bean Life Cycle

    We can specify some life cycle callback methods to complete some custom operations at a specific moment in the Spring Bean life cycle and manage the Bean life cycle.

There are two main methods of bean life cycle callback:

  • Initialization callback method: invoked after the Spring Bean is initialized to perform some custom callback operations.

  • Destruction callback method: invoked before the Spring Bean is destroyed to perform some custom callback operations.

We can customize the life cycle callback method of the Bean in the following three ways:

  • Implemented through the interface

  • Implemented through XML configuration

  • Implemented using annotations

    If there are multiple life cycle callback methods in a bean, the order of priority is: annotation > interface > XML configuration.

Dog.java:

public class Dog {
    private String name;
    private String owner;
    private int age;

    public Dog() {
        System.out.println("Dog对象被创建...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("调用setName方法....");
        this.name = name;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        System.out.println("调用setOwner方法....");
        this.owner = owner;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        System.out.println("调用setAge方法....");
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", owner='" + owner + '\'' +
                ", age=" + age +
                '}';
    }
}

applicationContext.xml:

<bean id="dog" class="com.newcapec.bean.Dog" p:name="旺财" p:owner="小明" p:age="5"/>

test:

public class LifeCycleTest {
    @Test
    public void testLifeCycle() {
        System.out.println("-------容器初始化阶段---------");
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        System.out.println("-------对象使用阶段---------");
        Dog dog = ac.getBean("dog", Dog.class);
        System.out.println(dog);

        System.out.println("-------容器关闭阶段---------");
        //手动关闭容器
        ac.close();//ApplicationContext没有close()
    }
}
  • 2.8.2.1 Implemented through interfaces

    We can specify the life cycle callback method of the Bean by implementing the InitializingBean and DisposableBean interfaces in the Java class of the Spring Bean.
    
    Note: In general, we do not recommend specifying the life cycle callback method in this way, because this way will lead to high coupling of the code.

callback method interface method illustrate
initialization callback InitializingBean afterPropertiesSet() Specify the initialization callback method, which will be called after the Spring Bean is initialized to perform some custom callback operations.
destroy callback DisposableBean destroy() Specify the destruction callback method, which will be called before the Spring Bean is destroyed, and perform some custom callback operations.

Dog.java:

public class Dog implements InitializingBean, DisposableBean {
    private String name;
    private String owner;
    private int age;

    public Dog() {
        System.out.println("Dog对象被创建...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("调用setName方法....");
        this.name = name;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        System.out.println("调用setOwner方法....");
        this.owner = owner;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        System.out.println("调用setAge方法....");
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", owner='" + owner + '\'' +
                ", age=" + age +
                '}';
    }

    /**
     * 初始化回调逻辑
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(" 调用接口:InitializingBean,方法:afterPropertiesSet,无参数");
    }
    /**
     * 销毁回调逻辑
     *
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        System.out.println(" 调用接口:DisposableBean,方法:destroy,无参数");
    }
}
  • 2.8.2.2 Implementation via XML configuration

    We can also specify the life cycle callback method of the Bean through the init-method and destroy-method attributes in the <bean> element in Spring's XML configuration.

XML configuration properties describe
init-method Specify the initialization callback method, which will be called after the Spring Bean is initialized to perform some custom callback operations.
destory-method Specify the destruction callback method, which will be called before the Spring Bean is destroyed, and perform some custom callback operations.

Dog.java:

public class Dog {
    private String name;
    private String owner;
    private int age;

    public Dog() {
        System.out.println("Dog对象被创建...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("调用setName方法....");
        this.name = name;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        System.out.println("调用setOwner方法....");
        this.owner = owner;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        System.out.println("调用setAge方法....");
        this.age = age;
    }

    public void init(){
        System.out.println("Dog对象的初始化方法...");
    }
    
    public void destroy(){
        System.out.println("Dog对象的销毁方法...");
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", owner='" + owner + '\'' +
                ", age=" + age +
                '}';
    }
}

applicationContext.xml:

<bean id="dog" class="com.newcapec.bean.Dog" p:name="旺财" p:owner="小明" p:age="5"  
      init-method="init" destroy-method="destroy"/>

2.9 Relationship between beans

2.9.1 Inheritance relationship

  • Spring allows the configuration of inherited beans, and the inherited bean is called the parent bean. A bean that inherits from this parent bean is called a child bean;

  • The child bean inherits the configuration from the parent bean, including the property configuration of the bean;

  • Child beans can also override the configuration inherited from the parent bean;

  • 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 template, you can set <bean>the abstract attribute to true, so that Spring will not instantiate this bean;

  • Not <bean>all attributes in an element are inherited. For example: autowire, abstract, etc.;

  • You can also ignore the class attribute of the parent bean (no need to create a parent bean object, just provide a template for the child bean), let the child bean specify its own class, and share the same attribute configuration. But at this time abstract must be set to true;

Animal.java:

public class Animal {
    private String name;
    private Integer age;

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

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

applicationContext.xml:

<!-- bean之间的继承关系 -->
<bean id="animal" class="com.newcapec.bean.Animal">
    <property name="name" value="动物"></property>
    <property name="age" value="10"></property>
</bean>
<bean id="dog" class="com.newcapec.bean.Dog" parent="animal">
    <property name="name" value="小狗"></property>
    <property name="owner" value="小黑"></property>
</bean>

test:

public class RelationTest {
    @Test
    public void testExtends() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Dog dog = ac.getBean("dog", Dog.class);
        System.out.println(dog);
    }
}

Define the template:

    In the definition of the parent Bean, there is a very important attribute, that is the abstract attribute. If the abstract attribute value of a parent Bean is true, it indicates that the Bean is abstract.

    The abstract parent Bean can only be inherited by the child Bean as a template, it cannot be instantiated, nor can it be referenced by other Beans, and it cannot be obtained by calling the getBean() method according to the id in the code, otherwise an error will be returned.

    In the definition of the parent bean, either specify the class attribute or not specify the class attribute. If the parent Bean definition does not explicitly specify the class attribute, then the abstract attribute of the parent Bean must be true.

applicationContext.xml:

<!-- bean模版 -->
<bean id="animal" abstract="true">
    <property name="name" value="动物"></property>
    <property name="age" value="10"></property>
</bean>

<bean id="dog" class="com.newcapec.bean.Dog" parent="animal">
    <property name="name" value="小狗"></property>
    <property name="owner" value="小黑"></property>
</bean>

2.9.2 Dependencies

  • Spring allows users to set the pre-dependent bean of the bean through the depends-on attribute, and the pre-dependent bean will be created before the bean is instantiated;

  • If the front depends on multiple beans, you can configure the bean name by comma or space;

Address.java:

public class Address {
    public Address() {
        System.out.println("Address对象创建了....");
    }
}

User.java:

public class User {
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public User() {
        System.out.println("User对象创建了....");
    }

    @Override
    public String toString() {
        return "User{" +
                "address=" + address +
                '}';
    }
}

applicationContext.xml:

<!-- bean之间的依赖关系 -->
<bean id="user" class="com.newcapec.bean.User" p:address-ref="address" depends-on="address"/>

<bean id="address" class="com.newcapec.bean.Address"/>

test:

public class RelationTest {
    @Test
    public void testDependsOn(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        User user = ac.getBean("user", User.class);
        System.out.println(user);
    }
}

2.10 Instantiate Bean via factory

2.10.1 Static factories

  • Calling a static factory method to create a bean encapsulates the process of object creation into a static method. When the client needs the object, it only needs to simply call the static method without caring about the details of creating the object;

  • To declare a bean created by a static method, you need to specify the class that owns the factory method in the bean's class attribute, and specify the name of the factory method in the factory-method attribute. Finally, use <constrctor-arg>the element to pass method parameters to the method;

Cat.java:

public class Cat {
    private String name;
    private int age;

    public Cat() {
    }

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

CatStaticFactory.java:

/**
 * 一个用于创建cat对象的静态工厂
 */
public class CatStaticFactory {
    /**
     * 提供一个创建对象的静态方法
     */
    public static Cat getInstance(String name, int age){
        return new Cat(name, age);
    }
}

applicationContext.xml:

<!-- 静态工厂-->
<bean id="cat1" class="com.newcapec.factory.CatStaticFactory" factory-method="getInstance">
    <constructor-arg value="汤姆猫"/>
    <constructor-arg value="2"/>
</bean>

test:

public class FactoryTest {
    @Test
    public void testStaticFactory() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Cat cat = ac.getBean("cat1", Cat.class);
        System.out.println(cat);
    }
}

2.10.2 Instance factory

  • Encapsulate the creation process of an object into a method of another object instance. When the client needs to request an object, it only needs to simply call the instance method without caring about the details of object creation;

  • To declare a bean created by an instance factory method, <bean>specify the bean that owns the factory method in the factory-bean attribute, and specify the name of the factory method in the factory-method attribute. Finally, use <construtor-arg>tags to pass method parameters to factory methods;

CatInstanceFactory.java:

/**
 * 一个用于创建cat对象的实例工厂
 */
public class CatInstanceFactory {
    /**
     * 提供一个创建对象的非静态方法
     */
    public Cat getInstance(String name, int age){
        return new Cat(name, age);
    }
}

applicationContext.xml:

<!-- 实例工厂-->
<bean id="instanceFactory" class="com.newcapec.factory.CatInstanceFactory"/>

<bean id="cat2" factory-bean="instanceFactory" factory-method="getInstance">
    <constructor-arg value="波斯猫"/>
    <constructor-arg value="3"/>
</bean>

test:

public class FactoryTest {
    @Test
    public void testInstanceFactory() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Cat cat = ac.getBean("cat2", Cat.class);
        System.out.println(cat);
    }
}

2.11 FactoryBean instantiates Bean

  • There are two types of beans in Spring, one is a normal bean, and the other is a factory bean, FactoryBean;

  • The factory bean is different from the normal bean, the object it returns is not an instance of the specified class, it returns the object returned by the getObject method of the factory bean;

CatFactoryBean.java:

public class CatFactoryBean implements FactoryBean<Cat> {
    private String name;
    private int age;

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

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取对象
     */
    @Override
    public Cat getObject() throws Exception {
        return new Cat(name, age);
    }

    /**
     * 生成对象的Class类型
     */
    @Override
    public Class<?> getObjectType() {
        return Cat.class;
    }

    /**
     * 设置该对象是否为单例模式
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

applicationContext.xml:

<!-- FactoryBean配置bean -->
<bean id="cat3" class="com.newcapec.factory.CatFactoryBean">
    <property name="name" value="加菲猫"/>
    <property name="age" value="5"/>
</bean>

test:

public class FactoryTest {
    @Test
    public void testFactoryBean(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Cat cat = ac.getBean("cat3", Cat.class);
        System.out.println(cat);
    }
}

2.12 <beans>Commonly used attributes or sub-elements of elements

    The <beans> element of the XML configuration can contain multiple attributes or sub-elements, and the commonly used attributes or sub-elements are shown in the following table.

attribute name describe
id The unique identifier of the bean, and the configuration and management of the bean by the Spring IoC container are completed through this property. The value of id must start with a letter, and symbols such as letters, numbers, and underscores can be used.
name This attribute represents the name of the Bean. We can specify multiple names for the same Bean through the name attribute, and each name is separated by a comma or a semicolon. The Spring container can configure and manage the Bean in the container through the name attribute.
class This attribute specifies the specific implementation class of the Bean, which must be a complete class name, that is, the fully qualified name of the class.
scope Indicates the scope of the Bean, and the attribute value can be singleton (singleton), prototype (prototype), request, session and global Session. The default value is singleton.
constructor-arg <bean>The child element of the element, we can pass in the construction parameters through this element to realize the instantiation of the Bean. The index attribute of this element specifies the serial number of the construction parameter (starting from 0), and the type attribute specifies the type of the construction parameter.
property <bean>The sub-element of the element is used to call the setter method in the Bean instance to assign values ​​to the properties, thus completing the property injection. The name attribute of this element is used to specify the corresponding property name in the Bean instance.
ref <property><constructor-arg> 等元素的子元索,用于指定对某个 Bean 实例的引用,即 <bean> 元素中的 id 或 name 属性。
value <property><constractor-arg> 等元素的子元素,用于直接指定一个常量值。
list 用于封装 List 或数组类型的属性注入。
set 用于封装 Set 类型的属性注入。
map 用于封装 Map 类型的属性注入。
entry <map> 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值。
init-method 容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法
destroy-method 容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效
lazy-init 懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效

Guess you like

Origin blog.csdn.net/ligonglanyuan/article/details/124567965