Spring
- Spring6 enables Log4j2 logging framework
- dependency injection
-
- set injection
-
- set injects simple types
-
- Classic case: injecting values into attributes of the data source:
- Inject into array
- Inject into List collection
- Inject Set collection
- Inject into Map collection
- constructor injection
Spring6 enables Log4j2 logging framework
Starting from Spring 5, the integrated logging framework supported by the Spring framework is Log4j2. How to enable the logging framework:
Step 1: Introduce Log4j2 dependencies
<!--log4j2 dependency--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.19.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> <version>2.19.0</version> </dependency>
Step 2: Provide the log4j2.xml configuration file under the root path of the class (the file name is fixed to: log4j2.xml, and the file must be placed under the class root path.)
<?xml version="1.0" encoding="UTF-8"?> <configuration> <loggers> <!-- level specifies the log level, from low to high priority: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <root level="DEBUG"> <appender-ref ref="spring6log"/> </root> </loggers> <appenders> <!--Output log information to the console--> <console name="spring6log" target="SYSTEM_OUT"> <!--Control the format of log output--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </console> </appenders> </configuration>
Step 3: Use the logging framework
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class); logger.info("I am a log message");
Dependency injection
● Dependency refers to the relationship between objects and objects.
● Injection refers to a data transfer behavior, which creates a relationship between objects and objects through injection behavior.
There are two common implementation methods of dependency injection:
● The first type: set injection
● The second type: constructor injection
New module: spring6-003-dependency-injection
set injection
Set injection is implemented based on the set method. The bottom layer will call the set method corresponding to the attribute through the reflection mechanism and then assign a value to the attribute. This method requires that the attribute must provide a set method to the outside world.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.powernode</groupId> <artifactId>spring6-002-dependency-injection</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <repositories> <repository> <id>repository.spring.milestone</id> <name>Spring Milestone Repository</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.0-M2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> </project>
UserDao.java
package com.w.spring6.dao; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UserDao {<!-- --> private static final Logger logger= LoggerFactory.getLogger(UserDao.class); public void insert(){<!-- --> //System.out.println("Database is saving information"); logger.info("Database is saving information"); } }
UserService.java
package com.w.spring6.service; import com.w.spring6.dao.UserDao; import com.w.spring6.dao.VipDao; public class UserService {<!-- --> private UserDao userDao; private VipDao vipDao; public void setAbc(VipDao vipDao){<!-- --> this.vipDao=vipDao; } //For set injection, a set method must be provided //spring container will call this set method to assign value to userDao /* //What I wrote does not comply with the javabean specification public void setMySQLUserDao(UserDao xyz){ this.userDao=xyz; }*/ //idea automatically generates compliance with javabean specifications public void setUserDao(UserDao userDao) {<!-- --> this.userDao = userDao; } public void saveUser(){<!-- --> userDao.insert(); vipDao.insert(); } }
spring.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 id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/> <bean id="userServiceBean" class="com.powernode.spring6.service.UserService"> <property name="userDao" ref="userDaoBean"/> </bean> </beans>
SpringDITest.java
package com.w.spring6.text; import com.w.spring6.bean.QianDaYe; import com.w.spring6.bean.User; import com.w.spring6.jdbc.MyDataSource; import com.w.spring6.service.CustomerService; import com.w.spring6.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDITest {<!-- --> @Test public void testSetDI(){<!-- --> ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = applicationContext.getBean("userServiceBean", UserService.class); userService.save(); } }
operation result:
Implementation principle:
Obtain the attribute name through the property tag: userDao
The set method name is inferred from the attribute name: setUserDao
Call the setUserDao() method through the reflection mechanism to assign values to properties.
The name of the property tag is the attribute name.
The ref of the property tag is the id of the bean object to be injected.
Summary: The core implementation principle of set injection: calling the set method through the reflection mechanism to assign values to properties and create a relationship between two objects.
set injects simple types
The previously injected object attribute was UserDao. How to write it when the object attribute is int type?
Example: Write a program to assign a value of 20 to the age attribute of a User object:
The first step: define the User class, provide the age attribute, and provide the setter method of the age attribute.
package com.w.spring6.bean; public class User {<!-- --> private String username; private String password; private int age; @Override public String toString() {<!-- --> return "User{" + "username='" + username + ''' + ", password='" + password + ''' + ", age=" + age + '}'; } }
Step 2: Write the spring configuration file: beans.xml, add
<!--Inject simple types--> <bean id="userBean" class="com.w.spring6.bean.User"> <property name="username" value="Zhang San"/> <property name="password" value="123"/> <property name="age" value="20"/> </bean>
Note: If assigning a value to a simple type, use the value attribute or value tag. instead of ref
Step 3: Write a test program
@Test public void testSimpleTypeSet() {<!-- --> ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans.xml"); User user=applicationContext.getBean("userBean", User.class); System.out.println(user); }
operation result:
Classic case: Injecting values into attributes of the data source:
Write a data source by yourself. All data sources must implement the javax.sql.DataSource interface, and the data source should have information to connect to the database, such as: driver, url, username, password, etc.
Step 1: Create a new MyDataSource.java, provide 4 properties, and provide a setter method.
package com.w.spring6.jdbc; import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; /* All data sources must implement the Java specification: java.sql.DataSource What is a data source: Anything that can provide you with a Connection object is a data source. */ public class MyDataSource implements DataSource {<!-- --> //The data source can be managed by the spring container private String driver; private String url; private String username; private String password; @Override public String toString() {<!-- --> return "MyDataSource{" + "driver='" + driver + ''' + ", url='" + url + ''' + ", username='" + username + ''' + ", password='" + password + ''' + '}'; } public void setDriver(String driver) {<!-- --> this.driver = driver; } public void setUrl(String url) {<!-- --> this.url = url; } public void setUsername(String username) {<!-- --> this.username = username; } public void setPassword(String password) {<!-- --> this.password = password; } @Override public Connection getConnection() throws SQLException {<!-- --> return null; } @Override public Connection getConnection(String username, String password) throws SQLException {<!-- --> return null; } @Override public PrintWriter getLogWriter() throws SQLException {<!-- --> return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException {<!-- --> } @Override public void setLoginTimeout(int seconds) throws SQLException {<!-- --> } @Override public int getLoginTimeout() throws SQLException {<!-- --> return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException {<!-- --> return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException {<!-- --> return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {<!-- --> return false; } }
Step 2: Write the spring configuration file: spring-properties.xml. We provide setter methods for the four properties of driver, url, username, and password. We can use spring’s dependency injection to complete the creation of data source objects and assignment of properties.
<?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"> <!-- Import external properties files Step 1: Introduce the context namespace Step 2: Use the tag location attribute to specify the path to the attribute configuration file --> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.w.spring6.jdbc.MyDataSource"> <property name="driver" value="${jdbc.driverClass}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> </beans>
Step 3: Write a test program
@Test public void testProperties() {<!-- --> ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-properties.xml"); MyDataSource da=applicationContext.getBean("dataSource", MyDataSource.class); System.out.println(da); }
operation result:
Inject array
When the elements in the array are simple types and not simple types
QianDaYe.java
package com.w.spring6.bean; import java.util.Arrays; public class QianDaYe {<!-- --> private String[] aiHaos; private Woman[] womens; @Override public String toString() {<!-- --> return "QianDaYe{" + "aiHaos=" + Arrays.toString(aiHaos) + ", womens=" + Arrays.toString(womens) + '}'; } public void setWomens(Woman[] womens) {<!-- --> this.womens = womens; } public void setAiHaos(String[] aiHaos) {<!-- --> this.aiHaos = aiHaos; } }
Woman.java
package com.w.spring6.bean; public class Woman {<!-- --> private String name; @Override public String toString() {<!-- --> return "Woman{" + "name='" + name + ''' + '}'; } public void setName(String name) {<!-- --> this.name = name; } }
spring-array.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 id="w1" class="com.w.spring6.bean.Woman"> <property name="name" value="小花"/> </bean> <bean id="w2" class="com.w.spring6.bean.Woman"> <property name="name" value="Xiaohong"/> </bean> <bean id="w3" class="com.w.spring6.bean.Woman"> <property name="name" value="Xiaoli"/> </bean> <bean id="yuQian" class="com.w.spring6.bean.QianDaYe"> <property name="aiHaos"> <array> <value>Smoking</value> <value>Drink</value> <value>Playing mahjong</value> </array> </property> <!-- This array is not a simple type--> <property name="womens"> <array> <ref bean="w1"/> <ref bean="w2"/> <ref bean="w3"/> </array> </property> </bean> </beans>
SpringDITest.java
@Test public void testArray() {<!-- --> ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-array.xml"); QianDaYe yuQian=applicationContext.getBean("yuQian", QianDaYe.class); System.out.println(yuQian); }
Test Results:
Inject List collection
List collection: ordered and repeatable
Note: Use the list tag when injecting a List collection. If the List collection is a simple type, use the value tag. Otherwise, use the ref tag.
People.java
package com.w.spring6.bean; import java.util.List; public class People {<!-- --> //A person has multiple names private List<String> names; public void setNames(List<String> names) {<!-- --> this.names = names; } @Override public String toString() {<!-- --> return "People{" + "names=" + names + '}'; } }
spring-collection.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 id="peopleBean" class="com.w.spring6.bean.People"> <property name="names"> <list> <value>Iron Hammer</value> <value>Zhang San</value> <value>Zhang San</value> <value>Zhang San</value> <value>Wolf</value> </list> </property> </bean> </beans>
test program:
@Test public void testCollection(){<!-- --> ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml"); People peopleBean = applicationContext.getBean("peopleBean", People.class); System.out.println(peopleBean); }
Test Results:
The subsequent Set collection and Map collection are the same and will not be demonstrated.
Inject Set collection
<set> <!--You can use ref for non-simple types, and value for simple types--> <value>110</value> <value>120</value> <value>119</value> </set>
Inject Map collection
<map> <!--If the key is not a simple type, use the key-ref attribute--> <!--If value is not a simple type, use the value-ref attribute--> <entry key="1" value="Beijing"/> <entry key="2" value="Shanghai"/> <entry key="3" value="Shenzhen"/> </map>
Construction injection
Core principle: assign values to properties by calling the constructor method.
OrderDao
package com.w.spring6.dao; public class OrderDao {<!-- --> public void deleteById(){<!-- --> System.out.println("Deleting order..."); } }
OrderService
package com.w.spring6.service; import com.w.spring6.dao.OrderDao; public class OrderService {<!-- --> private OrderDao orderDao; // Call the constructor through reflection mechanism to assign values to properties public OrderService(OrderDao orderDao) {<!-- --> this.orderDao = orderDao; } public void delete(){<!-- --> orderDao.deleteById(); } }
spring.xml added
<bean id="orderDaoBean" class="com.w.spring6.dao.OrderDao"/> <bean id="orderServiceBean" class="com.w.spring6.service.OrderService"> <!--index="0" indicates the first parameter of the constructor, and the orderDaoBean object is passed to the first parameter of the constructor. --> <constructor-arg index="0" ref="orderDaoBean"/> </bean>
test program:
SpringDITest.java
@Test public void testConstructorDI(){<!-- --> ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); OrderService orderServiceBean = applicationContext.getBean("orderServiceBean", OrderService.class); orderServiceBean.delete(); }
When injected through the constructor method:
● You can use subscripts
● You can pass the parameter name
● You do not need to specify the subscript and parameter name, and the type can be automatically inferred.