Spring IoC container and Bean management

Spring acquaintance IoC control r...
IoC control reversal
  DI dependency injection
Spring
Spring IoC container responsibilities
Spring IoC first experience
Implementation method:
Spring framework component module
  ApplicationContext implementation class
Instantiation of objects based on construction method
Factory instantiated objects
Extract from IoC container   Bean
Path matching expression
  Object dependency injection
Advantages of dependency injection
Injection collection object
View objects in container  
bean scope property
scope usage
bean scope attribute list
  Thread safety of singleton
Multiple cases of prototype  
bean lifecycle
Application of life cycle in actual combat
Three types of notes:
Java Config core annotation
Java Config initialization mode
Spring acquaintance

IoC control reversal

  • IoC control inversion, fully known as Inverse of Control, is a design concept
  • Agents create and manage objects, and consumers obtain objects through agents
  • The purpose of IoC is to reduce the direct coupling between programs

Solve what problem?

The direct drinking of objects leads to the rigid Association of objects, and the program is difficult to expand. For example, if customers want to eat all kinds of apples, they need customers to buy apples all over the world. It's very troublesome.

Add the Ioc container to manage the objects uniformly, so that the object association becomes weak coupling. Just like the above scenario: if there are vendors, customers don't have to go everywhere to buy fruit. After the vendors buy, customers buy responsive apples according to their own needs.

  DI dependency injection

  • IoC is a design concept, a standard followed by modern programming and a grand goal
  • DI(Dependency Injection) is a specific technical implementation and a micro implementation
  • DI uses reflection technology in Java, which is object injection

Spring

meaning  

  • Spring can be viewed from both narrow and broad perspectives
  • In a narrow sense, Spring refers to the Spring framework
  • In a broad sense, Spring refers to the Spring ecosystem

Narrow Spring framework

  • The Spring framework is a one-stop solution to the complexity of enterprise development
  • The core of SPring framework is IoC container and AOP aspect oriented programming
  • Spring IoC is responsible for creating and managing system objects and extending functions on this basis

Generalized Spring ecosystem

Spring IoC container

IoC container is the foundation of Spring ecology, which is used to uniformly create and manage object dependencies

  As above: the Spring IoC container injects A's dependent B objects, and users only need to extract them.

Spring IoC container responsibilities

  • The control of the object is uniformly managed by a third party (IoC control reversal)
  • Using Java reflection technology to realize runtime object creation and Association (DI dependency injection)
  • Improving maintainability and scalability of applications based on configuration

Spring IoC first experience

eg: for example, three children Lily, Andy and Luna like to eat sweet, sour and soft apples respectively. There are three apples on the plate: Red Fuji, green apple and Jin Shuai.

How do children get their favorite apples?

Apple.class

package com.imooc.spring.ioc.entity; public class Apple { private String title; private String color; private String origin; public Apple() { //System.out.println("Apple object has been created," + this); } public Apple(String title, String color, String origin) { this.title = title; this.color = color; this.origin = origin; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } }

Child.class

package com.imooc.spring.ioc.entity; public class Child { private String name; private Apple apple; public Child() { } public Child(String name, Apple apple) { this.name = name; this.apple = apple; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Apple getApple() { return apple; } public void setApple(Apple apple) { this.apple = apple; } public void eat() { System.out.println(name + "Yes" + apple.getOrigin() + "Planted" + apple.getTitle()); } }

Traditional way:

Application.class

public class Application { public static void main(String[] args) { Apple apple1 = new Apple("Red Fuji", "gules", "Europe"); Apple apple2 = new Apple("green apple", "green", "Central Asia"); Apple apple3 = new Apple("Jin Shuai", "yellow", "China"); Child lily = new Child("Lily", apple1); Child andy = new Child("Andy", apple2); Child luna = new Child("Luna", apple3); lily.eat(); andy.eat(); luna.eat(); } }

Output results:

But this will have a disadvantage. If we need to change our favorite Apple later, we need to modify it here in the source code. In the development process, the source code often involves a lot of content, the modification is complex, it is easy to affect other places, and it is easy to make mistakes.

How to use IoC container:

Create the applicationcontext.xml file in the resources directory:

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- stay IoC When the container starts,Automatically by Spring instantiation Apple object,Name sweetApple Put into container --> <bean id="sweetApple"> <property name="title" value="Red Fuji"></property> <property name="origin" value="Europe"></property> <property name="color" value="gules"></property> </bean> <bean id="sourApple"> <property name="title" value="green apple"></property> <property name="origin" value="Central Asia"></property> <property name="color" value="green"></property> </bean> <bean id="softApple"> <property name="title" value="Jin Shuai"></property> <property name="origin" value="China"></property> <property name="color" value="yellow"></property> </bean> <bean id="rdApple"> <property name="title" value="Snake fruit"></property> <property name="origin" value="U.S.A"></property> <property name="color" value="gules"></property> </bean> <bean id="lily"> <property name="name" value="Lily"/> <property name="apple" ref="softApple"/> </bean> <bean id="andy"> <property name="name" value="Andy"/> <property name="apple" ref="rdApple"/> </bean> <bean id="luna"> <property name="name" value="Luna"/> <property name="apple" ref="sweetApple"/> </bean> </beans>

SpringApplication.class

public class SpringApplication { public static void main(String[] args) { //Create a Spring IoC container and instantiate objects in the container according to the configuration file ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Apple sweetApple = context.getBean("sweetApple", Apple.class); System.out.println(sweetApple.getTitle()); //Extract the object with beanId=lily from the IoC container Child lily = context.getBean("lily", Child.class); lily.eat(); Child andy = context.getBean("andy", Child.class); andy.eat(); Child luna = context.getBean("luna", Child.class); luna.eat(); } }

Execution results:

The advantage of this is that when it comes to modification, we only need to modify the content in applicationContent.xml

  Using XML to implement Spring IoC

  applicationContext.xml mentioned above is a way to implement Spring IoC by using XML files.

Implementation method:

  1. Instantiation of objects based on construction method
  2. Based on dynamic factory instantiation
  3. Factory instance based method instantiation

Spring framework component module

  ApplicationContext implementation class

  • ClassPathXmlApplicationContext
  • AnnotationConfigApplicationContext
  • WebApplicationContext

Instantiation of objects based on construction method

Default construction method

In the applicationContext.xml file:

<!--bean Labels create objects using the default construction method--> <bean id="apple1">

In Apple.class, it is modified as:

public Apple() { System.out.println("Apple Object created," + this); }

Printout:

Structural method with parameters

applicationContext.xml

<!--Instantiate an object using the parameterized construction method--> <bean name="apple2"> <constructor-arg name="title" value="Red Fuji"/> <constructor-arg name="color" value="gules"/> <constructor-arg name="origin" value="Europe"/> <constructor-arg name="price" value="19.8"/> </bean> <bean id="apple3"> <constructor-arg index="0" value="Red Fuji"/> <constructor-arg index="1" value="Europe"/> <constructor-arg index="2" value="gules"/> <constructor-arg index="3" value="19.8"/> </bean>

Apple.class

public Apple(String title, String origin, String color, Float price) { System.out.println("Creating objects with parametric construction methods, " + this); this.title = title; this.color = color; this.origin = origin; this.price = price; }

Printout:

Factory instantiated objects

Static factory

/** * Static factory creates objects through static methods to hide the details of creating objects */ public class AppleStaticFactory { public static Apple createSweetApple(){ //logger.info("") Apple apple = new Apple(); apple.setTitle("Red Fuji"); apple.setOrigin("Europe"); apple.setColor("gules"); return apple; } }

In applicationContext.xml

<!--Get objects using static factories--> <bean id="apple4" factory-method="createSweetApple"/>

Test:

Apple apple4 = context.getBean("apple4", Apple.class); System.out.println(apple4.getTitle());

  Output:

Factory example

/** * Factory instance method creation object refers to the process that IoC container instantiates the factory class and calls the corresponding instance method to create an object */ public class AppleFactoryInstance { public Apple createSweetApple(){ Apple apple = new Apple(); apple.setTitle("Red Fuji"); apple.setOrigin("Europe"); apple.setColor("gules"); return apple; } }

In applicationContext.xml

<!--Get objects using factory instance method--> <bean id="factoryInstance"/> <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>

Then test the output

Extract from IoC container   Bean

Mode 1: Apple apple = context.getBean("apple", Apple.class); Mode 2: Apple apple = (Apple)context.getBean("apple");

Recommended usage 1

The id and name attributes are the same

  • Both bean id and name are unique identifiers of the setting object in the IoC container
  • Both are not allowed to duplicate in the same configuration file
  • Both allow duplication in multiple configuration files, and the new object overwrites the old object

Differences between id and name attributes

  • id requirements are more stringent. Only one object id can be defined at a time (recommended)
  • name is more relaxed, allowing multiple object IDs to be defined at a time
  • Tips: the naming requirements of ID and name are meaningful and written according to the hump name
<bean name="apple2,apple7"> <constructor-arg name="title" value="Fuji 2"/> <constructor-arg name="color" value="gules"/> <constructor-arg name="origin" value="Europe"/> <constructor-arg name="price" value="29.8"/> </bean> <!-- No, id And name of bean The full name of the class is used as the default bean identification --> <bean> <constructor-arg name="title" value="Fuji 3"/> <constructor-arg name="color" value="gules"/> <constructor-arg name="origin" value="Europe"/> <constructor-arg name="price" value="29.8"/> </bean>

Path matching expression

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

  Load multiple profiles:

String[] configLocations = new String[]{"classpath:applicationContext.xml","classpath:applicationContext-1.xml"}; //Initialize the IoC container and instantiate the object ApplicationContext context = new ClassPathXmlApplicationContext(configLocations);

Path expression

  Object dependency injection

Dependency injection refers to the operation of assigning objects in the container to other objects by reflection at run time

  •   Object injection based on setter method
  • Injecting objects based on construction method

Object injection based on setter method

< property name = "" value = "" / >: static property

< property name = "" ref = "" / >: dynamic properties

<bean id="sweetApple"> <!-- IoC The container automatically invokes the runtime using the reflection mechanism setXXX Method to assign a value to a property --> <property name="title" value="Red Fuji"/> <property name="color" value="gules"/> <property name="origin" value="Europe"/> <property name="price" value="19.8"/> </bean> <bean id="lily"> <property name="name" value="Lily"/> <!-- utilize ref Inject dependent objects --> <property name="apple" ref="sweetApple"/> </bean>

Advantages of dependency injection

give an example:

applicationContext-dao.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookDao"> </bean> </beans>

applicationContext-serice.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookService"> <!--id=bookDao--> <property name="bookDao" ref="bookDao"/> </bean> </beans>

BookDao

public interface BookDao { public void insert(); }

BookDaoImpl

public class BookDaoImpl implements BookDao { public void insert() { System.out.println("towards MySQL Book Insert a piece of data into the table"); } }

BookService

public class BookService { private BookDao bookDao ; public void purchase(){ System.out.println("Executing book purchase business method"); bookDao.insert(); } public BookDao getBookDao() { return bookDao; } public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }

BookShopApplication

public class BookShopApplication { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-*.xml"); BookService bookService = context.getBean("bookService", BookService.class); bookService.purchase(); } }

Output:

Advantages: for example, the database is migrated from MySQL to Oracle. At this time, you only need to change the class of BookDao Bean to Oracle

Injection collection object

  Inject List

Injection set

Injection map  

Inject Properties  

  key and value in Properties can only be String type

View objects in container  

//Gets an array of all beanids in the container String[] beanNames = context.getBeanDefinitionNames(); for (String beanName:beanNames){ System.out.println(beanName); System.out.println("type:" + context.getBean(beanName).getClass().getName()); System.out.println("content:" + context.getBean(beanName)); }
Computer computer = context.getBean("com.imooc.spring.ioc.entity.Computer", Computer.class);

When there are multiple beans of the same class:

<bean> <constructor-arg name="brand" value="MICROSTAR"/> <constructor-arg name="type" value="Desktop"/> <constructor-arg name="sn" value="8389280012"/> <constructor-arg name="price" value="3000"/> </bean> <bean> <constructor-arg name="brand" value="ASUS"/> <constructor-arg name="type" value="notebook"/> <constructor-arg name="sn" value="9089380012"/> <constructor-arg name="price" value="6000"/> </bean>
Computer computer1 = context.getBean("com.imooc.spring.ioc.entity.Computer#0", Computer.class); Computer computer1 = context.getBean("com.imooc.spring.ioc.entity.Computer#1", Computer.class);

Scope and life cycle of Bean object

bean scope property

  • The bean scope property is used to determine when an object is created and scope
  • The bean scope configuration will affect the number of objects in the container
  • By default, bean s will be instantiated automatically after the IoC container is created, which is globally unique

scope usage

bean scope attribute list

  Thread safety of singleton

singleton is a single instance of multi-threaded execution in the container, which has thread safety risks  

Under single thread:

In multithreading: after user A operates a.setNum(1), user B operates a.setNum(2) in another thread  . At this time, 2 will appear when user A prints a.num, which is different from the setting value of user A

Multiple cases of prototype  

prototype has multiple instances in the container, occupying more resources, and there is no thread safety problem  

Comparison between singleton and prototype

bean lifecycle

Detail adjustment

  •   prototype enables object creation with init_method delay to execution of business
  • prototype makes the object no longer managed by the IoC container and no longer triggers the destroy method
  • Delaying loading the lazy init attribute delays object creation and initialization until the code execution phase

Application of life cycle in actual combat

Initialization of singleton and prototype

Initialization of singleton:

In 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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao"/> </beans>

Add in spring application:

public class SpringApplication { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); } }

Printout:

That is, when the IoC container is initialized, bean s are created for us  

prototype initialization:

  In 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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" scope="prototype"/> </beans>

Then test in spring application:

public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); System.out.println("======IoC Container initialized======="); UserDao userDao1 = context.getBean("userDao", UserDao.class); }

Output is:

That is, when the IoC container is created, it does not initialize the bean object for us, but only when we obtain the object. The initialization order of the singleton mode is consistent with the writing order.

Next, two bean objects will be initialized

<bean id="userDao" scope="prototype"/> <bean id="userService"> <property name="userDao" ref="userDao"/> </bean>

In most cases, Dao layer, server layer and control layer are singleton.

Implement a minimalist IoC container

Directory structure:

  Apple class

package com.imooc.spring.ioc.entity; public class Apple { private String title; private String color; private String origin; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } }

  Then add bean information in applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="sweetApple"> <property name="title" value="Red Fuji"/> <property name="color" value="gules"/> <property name="origin" value="Europe"/> </bean> </beans>

How to customize the logging profile:

Interface: ApplicationContext

package com.imooc.spring.ioc.context; public interface ApplicationContext { public Object getBean(String beanId); }

Implementation class ClassPathXmlApplicationContext  

public class ClassPathXmlApplicationContext implements ApplicationContext { private Map iocContainer = new HashMap(); /** * Read configuration file */ public ClassPathXmlApplicationContext() { try { String filePath = this.getClass().getResource("/applicationContext.xml").getPath(); // URL decoding filePath = new URLDecoder().decode(filePath, "UTF-8"); /** * Introducing dom4j and jaxen * Dom4j Is an XML parsing component of Java * Jaxen Is an Xpath expression interpreter */ SAXReader reader = new SAXReader(); Document document = reader.read(new File(filePath)); // Read "bean" tag List<Node> beans = document.getRootElement().selectNodes("bean"); for (Node node : beans) { Element ele = (Element) node; String id = ele.attributeValue("id"); String className = ele.attributeValue("class"); Class c = Class.forName(className); Object obj = c.newInstance(); List<Node> properties = ele.selectNodes("property"); for (Node p : properties) { Element property = (Element) p; String propName = property.attributeValue("name"); String propValue = property.attributeValue("value"); // set method String setMethodName = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1); System.out.println("Ready to execute" + setMethodName + "Method injection data"); Method setMethod = c.getMethod(setMethodName, String.class); setMethod.invoke(obj, propValue);//Inject data through setter method } iocContainer.put(id, obj); } System.out.println(iocContainer); System.out.println("IOC Container initialization completed"); } catch (Exception e) { e.printStackTrace(); } } public Object getBean(String beanId) { return iocContainer.get(beanId); } }

Then test:

public class Application { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext(); Apple apple = (Apple)context.getBean("sweetApple"); System.out.println(apple); } }

Execution results:

Implementing Spring IoC with annotations

Annotation based advantages

  • Get rid of cumbersome XML bean s and dependency injection configuration
  • Based on the "declarative" principle, it is more suitable for lightweight modern enterprise applications
  • Make the code more readable, and the R & D personnel have a better development experience

Three types of notes:

  1. Component type annotation - declares the functions and functions of the current class
  2. Auto assembly annotation - automatically inject objects according to special attributes
  3. Metadata annotation - more detailed annotation of auxiliary IoC container management objects

Annotation of four component types

  1. @Compponent   : Component annotation, general annotation, and the class described by this annotation will be managed and instantiated by the IoC container
  2. @Controller   : Semantic annotation, indicating that the current class is the controller class in MVC application
  3. @Service.: semantic annotation indicating that the current class is a service business service class
  4. @Repository: semantic annotation, which indicates that the current class is used for the business persistence layer, and usually describes the corresponding Dao class

Two types of automatic assembly annotation

  1. Assemble by type
    1. @Autowired: dynamically inject attributes according to the object type in the container, which is provided by the Spring mechanism
    2. @Inject: Based on JSR-330(Dependency Injection for Java) standard, the others are the same as @ Autowired, but the required attribute is not supported
  2. Assemble by name
    1. @Named: used with @ Inject, JSR-330 specification, automatically assemble attributes by attribute name
    2. @Resource: Based on JSR-330 specification, intelligent matching is preferred by name and then by type

Metadata annotation

@Read properties file for Value

@Value("com.imooc") private String config;

It is equivalent to that during initialization, the value of config is "com.inooc", and the main user loads the data in the configuration file: @ Value("$")

Using Java Config to implement Spring IoC

Advantages based on Java Config

  • Completely get rid of the shackles of XML and use independent Java classes to manage objects and dependencies
  • The annotation configuration is relatively decentralized, and the configuration can be centrally managed by using Java Config
  • Dependency checking can be performed at compile time, which is not error prone

Java Config core annotation

Java Config initialization mode

  give an example:

package com.imooc.spring.ioc; import com.imooc.spring.ioc.controller.UserController; import com.imooc.spring.ioc.dao.EmployeeDao; import com.imooc.spring.ioc.dao.UserDao; import com.imooc.spring.ioc.service.UserService; import org.springframework.context.annotation.*; @Configuration //The current class is a configuration class that replaces applicationContext.xml @ComponentScan(basePackages = "com.imooc") public class Config { @Bean //Java Config uses methods to create objects, puts the returned object of the method into the container, and beanId = method name public UserDao userDao(){ UserDao userDao = new UserDao(); System.out.println("Created" + userDao); return userDao; } @Bean //Java Config uses methods to create objects, puts the returned object of the method into the container, and beanId = method name @Primary public UserDao userDao1(){ UserDao userDao = new UserDao(); System.out.println("Created" + userDao); return userDao; } @Bean //Try to inject by name first. If name does not exist, inject by type public UserService userService(UserDao udao , EmployeeDao employeeDao){ UserService userService = new UserService(); System.out.println("Created" + userService); userService.setUserDao(udao); System.out.println("call setUserDao:" + udao); userService.setEmployeeDao(employeeDao); return userService; } @Bean //<bean id="xxx" clas="xxx"> @Scope("prototype") public UserController userController(UserService userService){ UserController userController = new UserController(); System.out.println("Created" + userController); userController.setUserService(userService); System.out.println("call setUserService:" + userService); return userController; } }

Test:

public class SpringApplication { public static void main(String[] args) { //Configuring initialization of IoC container based on Java Config ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); System.out.println("========================="); String[] ids = context.getBeanDefinitionNames(); for(String id : ids){ System.out.println(id + ":" + context.getBean(id)); } } }

23 October 2021, 07:11 | Views: 6022

Add new comment

For adding a comment, please log in
or create account

0 comments