spring6 note 2 (ioc, bean scope, factory pattern, four instantiation methods of bean, life cycle)

Chapter 4, Spring's implementation of ioc

4.4 p namespace injection

Purpose: Simplify configuration.

The prerequisites for using p namespace injection include two:

  • First: Add the configuration information of the p namespace in the XML header information: xmlns:p=" http://www.springframework.org/schema/p"
  • Second: p namespace injection is based on the setter method, so the corresponding attribute needs to provide the setter method.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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="customerBean" class="com.powernode.spring6.beans.Customer" p:name="zhangsan" p:age="20"/>

</beans>

4.5 c namespace injection

The c namespace is injected by the simplified constructor.

Two prerequisites for using the c namespace:

First: You need to add information to the header of the xml configuration file: xmlns:c="http://www.springframework.org/schema/c"

Second: You need to provide a construction method.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       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="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:year="1970" c:month="1" c:day="1"/>-->

    <bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/>

</beans>

4.6 util namespace

Using the util namespace allows configuration reuse.

The prerequisite for using the util namespace is to add configuration information to the header of the spring configuration file. 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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <util:properties id="prop">
        <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </util:properties>

    <bean id="dataSource1" class="com.powernode.spring6.beans.MyDataSource1">
        <property name="properties" ref="prop"/>
    </bean>

    <bean id="dataSource2" class="com.powernode.spring6.beans.MyDataSource2">
        <property name="properties" ref="prop"/>
    </bean>
</beans>

4.7 XML-based autowiring

Spring can also complete automatic injection, which is also called automatic assembly. It can be autowired by name or by type.

In addition to using attribute assembly in xml, automatic assembly can also be completed according to name or type

<?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="userService" class="com.powernode.spring6.service.UserService" autowire="byName"/>
    
    <bean id="aaa" class="com.powernode.spring6.dao.UserDao"/>

</beans>

There is a UserDao object named aaa in the userService here, here you can complete the automatic assembly according to the name

This configuration plays a key role:

  • autowire="byName" needs to be added to the UserService Bean, indicating that it is assembled by name.
  • There is a UserDao attribute in the UserService class, and the name of the UserDao attribute is aaa, and the corresponding set method is setAaa(), which happens to be the same as the id of the UserDao Bean. This is autowiring by name.

4.7.2 Autowiring by type

<?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">

    <!--byType Represents autowiring by type-->
    <bean id="accountService" class="com.powernode.spring6.service.AccountService" autowire="byType"/>

    <bean class="com.powernode.spring6.dao.AccountDao"/>

</beans>

Automatic assembly according to the type does not need to take the id name for the assembled bean, and will automatically look for it in the bean factory according to the type of AccountDao.

It can be seen that both byName and byType are based on the set method during assembly. So the set method must be provided. It is not acceptable to provide a constructor.

4.8 Spring introduces external attribute configuration files

First create a new jdbc file in the classpath

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=root123

Then use context to import in xml, and then you can use the value directly through the $ symbol.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="jdbc.properties"/>
    
    <bean id="dataSource" class="com.powernode.spring6.beans.MyDataSource">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
</beans>

The data source here is the data source written by myself. It is worth noting that the username here will limit the resolution of the name of the computer, so it is generally prefixed when using the database. jdbc.username

Chapter 5, the scope of bean s

By default, spring's ioc container is a singleton, and the bean object is created when the spring context is initialized. that is to execute

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
}

5.2 prototype

If you want Spring's Bean object to exist in the form of multiple instances, you can specify the value of the scope attribute in the bean tag: prototype, so that Spring will create a Bean object every time the getBean() method is executed, and it will be created after calling several times. several times.

<?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="sb" class="com.powernode.spring6.beans.SpringBean" scope="prototype" />

</beans>
@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");

    SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb1);

    SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb2);
}

the

5.3 Other scope s

The value of the scope attribute is more than two, and it includes a total of 8 options:

  • singleton: default, singleton.
  • prototype: prototype. Each time the getBean() method is called, a new Bean object is obtained. Or a new object every time it is injected.
  • request: A request corresponds to a Bean. Only for use in WEB applications.
  • session: A session corresponds to a Bean. Only for use in WEB applications.
  • global session: dedicated to portlet applications. If the global session is used in the Servlet WEB application, it has the same effect as the session. (Portlets and servlets are both specifications. Servlets run in servlet containers, such as Tomcat. Portlets run in portlet containers.)
  • application: An application corresponds to a Bean. Only for use in WEB applications.
  • websocket: A websocket life cycle corresponds to a Bean. Only for use in WEB applications.
  • Custom scope: Rarely used.

Chapter 6, Factory Model of GoF

  • Design Patterns: A solution that can be reused.
  • GoF (Gang of Four), Chinese name - group of four.
  • Design Patterns: Elements of Reusable Object-Oriented Software (aka Design Patterns), 1995 by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. These authors are often referred to as the "Gang of Four".
  • The book describes 23 design patterns. The design patterns we usually refer to refer to these 23 design patterns.
  • However, in addition to the GoF23 design patterns, there are other design patterns, such as: JavaEE design patterns (DAO pattern, MVC pattern, etc.).
  • The GoF 23 design patterns can be divided into three categories:
    • Creational (5): Solve object creation problems.
      • singleton pattern
      • factory method pattern
      • abstract factory pattern
      • builder mode
      • prototype pattern
    • Structural type (7): A classic structure in which some classes or objects are grouped together.
      • Proxy mode
      • decorator pattern
      • adapter pattern
      • combination mode
      • Flyweight mode
      • appearance mode
      • bridge mode
    • Behavioral (11): Solve the interaction problem between classes or objects.
      • strategy pattern
      • template method pattern
      • chain of responsibility model
      • Observer pattern
      • iterate over subpatterns
      • command mode
      • memo mode
      • state mode
      • visitor pattern
      • mediator pattern
      • interpreter mode
  • The factory pattern solves the problem of object creation, so the factory pattern belongs to the creational design pattern. Why learn the factory pattern here? This is because the Spring framework uses a large number of factory patterns at the bottom.

6.1 Three forms of factory mode

The factory pattern usually has three forms:

  • The first: Simple Factory pattern (Simple Factory): does not belong to one of the 23 design patterns. Simple factory pattern is also called: static factory method pattern. The simple factory pattern is a special implementation of the factory method pattern.
  • The second: Factory method pattern (Factory Method): It is one of the 23 design patterns.
  • The third: Abstract Factory pattern (Abstract Factory): It is one of the 23 design patterns.

6.2 Simple factory pattern

The role of the simple factory pattern includes three:

  • abstract product role
  • specific product role
  • factory class role

The code of the simple factory pattern is as follows:

Abstract product role: Weapon

public abstract class Weapon {
    /**
     * All weapons have aggressive behavior
     */
    public abstract void attack();
}

Specific product roles: Tank,Fighter

public class Tank extends Weapon{
    @Override
    public void attack() {
        System.out.println("Tanks fire!");
    }
}
public class Fighter extends Weapon{
    @Override
    public void attack() {
        System.out.println("Fighter planes drop atomic bombs!");
    }
}

Factory role: WeaponFactory
public class WeaponFactory {
    /**
     * Produce weapons according to different weapon types
     * @param weaponType weapon type
     * @return weapon object
     */
    public static Weapon get(String weaponType){
        if (weaponType == null || weaponType.trim().length() == 0) {
            return null;
        }
        Weapon weapon = null;
        if ("TANK".equals(weaponType)) {
            weapon = new Tank();
        } else if ("FIGHTER".equals(weaponType)) {
            weapon = new Fighter();
        } else if ("DAGGER".equals(weaponType)) {
            weapon = new Dagger();
        } else {
            throw new RuntimeException("This weapon is not supported!");
        }
        return weapon;
    }
}

test program

 

public class Client {
    public static void main(String[] args) {
        Weapon weapon1 = WeaponFactory.get("TANK");
        weapon1.attack();

        Weapon weapon2 = WeaponFactory.get("FIGHTER");
        weapon2.attack();

        Weapon weapon3 = WeaponFactory.get("DAGGER");
        weapon3.attack();
    }
}

Advantages of the simple factory pattern:

  • The client program does not need to care about the details of object creation. When it needs an object, it only needs to ask for it from the factory, which preliminarily realizes the separation of responsibilities. The client is only responsible for "consumption", and the factory is responsible for "production". Separation of production and consumption.

Disadvantages of simple factory pattern:

  • Disadvantage 1: The factory class concentrates the creation logic of all products, forming an omniscient and omnipotent class. Some people call it the God class. Obviously, the factory class is very critical and cannot go wrong. Once a problem occurs, the entire system will be paralyzed.
  • Disadvantage 2: It does not conform to the OCP opening and closing principle, and the factory class needs to be modified when the system is expanded.

The BeanFactory in Spring uses the simple factory pattern.

 

6.3 Factory method pattern

The factory method pattern not only retains the advantages of the simple factory pattern, but also solves the shortcomings of the simple factory pattern.

The roles of the factory method pattern include:

  • abstract factory role
  • Specific Factory Roles
  • abstract product role
  • specific product role

code show as below:

abstract product role

public abstract class Weapon {
    /**
     * All weapons have aggressive behavior
     */
    public abstract void attack();
}

specific product role Gun,Fighter

public class Gun extends Weapon{
    @Override
    public void attack() {
        System.out.println("Shoot!");
    }
}
public class Fighter extends Weapon{
    @Override
    public void attack() {
        System.out.println("A fighter jet launches a nuke!");
    }
}

abstract factory role
public interface WeaponFactory {
    Weapon get();
}

Specific Factory Roles GunFactory,FighterFactory

public class GunFactory implements WeaponFactory{
    @Override
    public Weapon get() {
        return new Gun();
    }
}

public class FighterFactory implements WeaponFactory{
    @Override
    public Weapon get() {
        return new Fighter();
    }
}

client

public class Client {
    public static void main(String[] args) {
        WeaponFactory factory = new GunFactory();
        Weapon weapon = factory.get();
        weapon.attack();

        WeaponFactory factory1 = new FighterFactory();
        Weapon weapon1 = factory1.get();
        weapon1.attack();
    }
}

If you want to expand a new product, you only need to add a product category, and then add a factory corresponding to the product.

We can see that there is no need to modify the previous source code when performing function extensions. Obviously, the factory method pattern conforms to the OCP principle.

Advantages of factory method pattern:

  • A caller who wants to create an object just needs to know its name.
  • High scalability, if you want to add a product, just extend a factory class.
  • The specific implementation of the product is shielded, and the caller only cares about the interface of the product.

Disadvantages of factory method pattern:

  • Every time a product is added, it is necessary to add a specific class and object implementation factory, which doubles the number of classes in the system, increases the complexity of the system to a certain extent, and also increases the dependence on the specific classes of the system. This is not a good thing.

Seven, Bean instantiation method

Spring provides multiple instantiation methods for Bean, usually including 4 methods. (That is to say, a variety of solutions are prepared for the creation of Bean objects in Spring, the purpose is: more flexible)

  • The first way: instantiate through the construction method
  • The second: instantiate through a simple factory pattern
  • The third: instantiate through factory-bean
  • The fourth type: instantiate through the FactoryBean interface

7.1 Instantiation via constructor

This is what we've been using before. By default, the Bean's parameterless constructor is called

7.2 Instantiation via simple factory pattern

Create a tool factory bean to help spring create objects.

public class VipFactory {
    public static Vip get(){
        return new Vip();
    }
}

<bean id="vipBean" class="com.powernode.spring6.bean.VipFactory" factory-method="get"/>

@Test
public void testSimpleFactory(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    Vip vip = applicationContext.getBean("vipBean", Vip.class);
    System.out.println(vip);
}

7.3 Instantiation via factory-bean

This approach is essentially: instantiation through the factory method pattern.

Create a factory bean by instantiating the object of the factory bean

public class OrderFactory {
    public Order get(){
        return new Order();
    }
}

<bean id="orderFactory" class="com.powernode.spring6.bean.OrderFactory"/>
<bean id="orderBean" factory-bean="orderFactory" factory-method="get"/>

@Test
public void testSelfFactoryBean(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    Order orderBean = applicationContext.getBean("orderBean", Order.class);
    System.out.println(orderBean);
}

 

7.4 Instantiation via FactoryBean interface

In the third method above, the factory-bean is our own definition, and the factory-method is also our own definition.

In Spring, when the class you write directly implements the FactoryBean interface, the factory-bean does not need to be specified, nor does the factory-method.

factory-bean will automatically point to the class that implements the FactoryBean interface, and factory-method will automatically point to the getObject() method.

public class PersonFactoryBean implements FactoryBean<Person> {

    @Override
    public Person getObject() throws Exception {
        return new Person();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        // true means singleton
        // false means prototype
        return true;
    }
}

<bean id="personBean" class="com.powernode.spring6.bean.PersonFactoryBean"/>

@Test
public void testFactoryBean(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    Person personBean = applicationContext.getBean("personBean", Person.class);
    System.out.println(personBean);

    Person personBean2 = applicationContext.getBean("personBean", Person.class);
    System.out.println(personBean2);
}

FactoryBean is an interface in Spring. Known as "Factory Bean". A "Factory Bean" is a special kind of Bean. All "factory beans" are used to assist the Spring framework to create other Bean objects.  

7.5 Difference between BeanFactory and FactoryBean

7.5.1 BeanFactory

The top-level object of the Spring IoC container, BeanFactory is translated as "Bean Factory". In Spring's IoC container, the "Bean Factory" is responsible for creating Bean objects.

BeanFactory is the factory.

7.5.2 FactoryBean

FactoryBean: It is a Bean, a Bean that can assist Spring in instantiating other Bean objects.

In Spring, beans can be divided into two categories:

  • The first category: common beans
  • The second type: factory Bean (remember: factory Bean is also a kind of Bean, but this kind of Bean is special, it can assist Spring to instantiate other Bean objects.)

 

7.6 Inject custom Date

As we said earlier, java.util.Date is regarded as a simple type in Spring, and simple types can be injected directly using the value attribute or value tag. But we have tested it before. For the Date type, when using the value attribute or value tag to assign a value, the format of the date string is very strict and must be in this format: Mon Oct 10 14:30:26 CST 2022.

A custom injection method can be realized by treating the time type as a complex type. At this time, factorybean is needed to complete the conversion of the time format.

public class DateFactoryBean implements FactoryBean<Date> {

    // Define a property to receive a date string
    private String date;

    // Assign a value to the date string attribute through the constructor
    public DateFactoryBean(String date) {
        this.date = date;
    }

    @Override
    public Date getObject() throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.parse(this.date);
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

Convert the input string type time to date type through this factory bean, and then inject this complex type into the simple date type through ref. .

<bean id="dateBean" class="com.powernode.spring6.bean.DateFactoryBean">
  <constructor-arg name="date" value="1999-10-11"/>
</bean>

<bean id="studentBean" class="com.powernode.spring6.bean.Student">
  <property name="birth" ref="dateBean"/>
</bean>

Eight, Bean life cycle

8.1 What is the life cycle of a Bean

Spring is actually a factory that manages Bean objects. It is responsible for object creation, object destruction, etc.

The so-called life cycle is: the entire process of an object from creation to final destruction.

When to create a Bean object?

What method will be called before and after creating the Bean object?

When is the Bean object destroyed?

What method is called before and after the destruction of the Bean object?

8.2 Why do you need to know the life cycle of Bean

In fact, the essence of the life cycle is: which method of which class is called at which time node.

We need to fully understand the special time nodes on this lifeline.

Only when we know where the special time nodes are, can we determine where the code is written.

We may need to execute a specific piece of code at a specific point in time, and this piece of code can be placed on this node. When the lifeline comes here, it will naturally be called.

8.3 The 5 steps of the Bean life cycle

For the management of the Bean life cycle, you can refer to the source code of Spring: the doCreateBean() method of the AbstractAutowireCapableBeanFactory class.

The Bean life cycle can be roughly divided into five major steps:

  • Step 1: Instantiate Bean: instantiate when creating a spring context in singleton mode
  • Step 2: Bean attribute assignment: call the set method assignment,
  • Step 3: Initialize the Bean: Execute the initBean method
  • Step 4: Use Bean: Use bean
  • Step 5: Destroy the Bean: the destruction method will only be executed when the spring container is closed

The initialization and destruction methods need to be specified in xml

<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
        <property name="name" value="zhangsan"/>
    </bean>

8.4 The 7 steps of the Bean life cycle

In the above 5 steps, the third step is to initialize the Bean. If you want to add code before and after initialization, you can add "Bean post-processor".

 **/
public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean post processor before Method execution, about to start initialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean post processor after Method execution, completed initialization");
        return bean;
    }
}

Configure the "Bean post-processor" in the spring.xml file:

<!--Configure the Bean post-processor. This post-processor will be applied to all bean s in the current configuration file. -->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

It must be noted that the Bean post-processor configured in the spring.xml file will act on all beans in the current configuration file.

 

8.5 10 steps of the Bean life cycle

If you track according to the source code, you can divide the steps into more fine-grained steps, 10 steps:

What does it mean to check whether the Bean implements the relevant interface of Aware in the above figure?

Aware-related interfaces include: BeanNameAware, BeanClassLoaderAware, BeanFactoryAware

  • When the Bean implements BeanNameAware, Spring will pass the Bean's name to the Bean.
  • When the Bean implements BeanClassLoaderAware, Spring will pass the class loader that loads the Bean to the Bean.
  • When the Bean implements BeanFactoryAware, Spring will pass the Bean factory object to the Bean.

After testing the above 10 steps, the User class can implement 5 interfaces and implement all methods:

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • InitializingBean
  • DisposableBean

8.6 Bean s have different scopes and different management methods

Spring chooses the management method according to the scope of the Bean.

  • For a singleton-scoped Bean, Spring can know exactly when the Bean is created, when it is initialized, and when it is destroyed;
  • For prototype-scoped beans, Spring is only responsible for creating them. When the container creates a Bean instance, the Bean instance is handed over to the client code for management, and the Spring container will no longer track its life cycle.

 

8.7 How to let Spring manage your own new objects

Sometimes we may encounter such a requirement. A certain java object is new by ourselves, and then we want this object to be managed by the Spring container. How to achieve it?

 

@Test
    public void testBeanRegister(){
        // own new object
        User user = new User();
        System.out.println(user);

        // Create a default listable BeanFactory object
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // Register Bean
        factory.registerSingleton("userBean", user);
        // Get the bean from the spring container
        User userBean = factory.getBean("userBean", User.class);
        System.out.println(userBean);
    }

Tags: Java Spring Front-end

Posted by jikishlove on Sun, 01 Jan 2023 18:02:42 +0530