2021-09-19 Spring5 IoC and DI Annotation Development

Spring5 IoC and DI Annotation Development

1 Spring Configuration Data Source

1.1 Role of data sources (connections)

  • Data sources (connection pools) are available to improve program performance
  • Pre-instantiate the data source to initialize partial connection resources
  • Get from data source when using connection resources
  • Return the connected resource to the data source after use
    Common data sources (connection pools): DBCP, C3P0, BoneCP, Druid, etc.

1.2 Steps to develop data sources

Manual creation of data sources

Database Data Source Dependency

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.4.0</version>
    <scope>test</scope>
</dependency>

Test Class

package com.raphuscucullatus.test;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.testng.annotations.Test;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

/**
 * c3p0 Druid Data Source Test Class
 *
 * @author raphus cucullatus
 * @version 2021/9/18 1:03
 * @since JDK8
 */
public class DataSourceTest {
    /**
     * Manually configure connection parameters to create a c3p0 data source
     */
    @Test
    public void testManualCreateDataSource() throws Exception {
        //create data source
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //Setting database connection parameters
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://127.168.2.8:3306/jdbc");
        dataSource.setUser("root");
        dataSource.setPassword("088.5741");
        //Get Connection Object
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

    }

    /**
     * Manually configure connection parameters to create Druid data sources
     */
    @Test
    public void testManualCreateDruidDataSource() throws SQLException {
        //create data source
        DruidDataSource dataSource = new DruidDataSource();
        //Setting database connection parameters
        dataSource.setPassword("root");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/jdbc");
        dataSource.setUsername("root");
        dataSource.setPassword("088.5741");
        //Get Connection Object
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }


    /**
     * Create c3p0 data source by reading configuration file
     */
    @Test
    public void testCreateDataSource() throws PropertyVetoException, SQLException {

        //jdbc.properties under load class path
        ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //Read profile information using resourceBundle
        dataSource.setDriverClass(resourceBundle.getString("jdbc.driver"));
        dataSource.setJdbcUrl(resourceBundle.getString("jdbc.url"));
        dataSource.setUser(resourceBundle.getString("jdbc.username"));
        dataSource.setPassword(resourceBundle.getString("jdbc.password"));
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();

    }

    /**
     * Create Druid Data Source by Reading Configuration File
     */
    @Test
    public void testCreateDruidDataSource() {
        DataSource dataSource;
        Properties properties = new Properties();
        try {
            properties.load(DataSourceTest.class.getClassLoader().getResourceAsStream("druiddatasource.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

c3p0 data source profile

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

druid data source profile

url=jdbc:mysql://127.0.0.1:3306/jdbc
username=root
password=088.5741
maxActive=20
initialSize=5
maxWait=6000
asyncInit=true

Decouple data source development from hard coding to configuration files

1.3 Spring Configuration Data Source

In addition to the database data source dependency of the response, you also import the spring dependency

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

Configure spring Core Profile

<?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="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jdbc"></property>
        <property name="user" value="root"></property>
        <property name="password" value="088.5741"></property>
    </bean>
</beans>

test

   /**
     * Generating a c3p0 data source from a spring container
     */
    @Test
    public void testSpringCreateDruidDataSource() throws SQLException {
        ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
//        DataSource dataSource = (DataSource)application.getBean("dataSource");
        DataSource dataSource = application.getBean(DataSource.class);
        Connection connection = dataSource.getConnection();
        System.out.println("adopt spring Container acquired connection:"+connection);
        connection.close();
    }

1.4 Spring Extraction Profile

Data Source Profile Information

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

spring Core Profile
Note: Attribute contenxt namespace needs to be added inside the beans tag (add in bold section below)

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

>

And add the following subtags inside the beans to bring in the external properties file (where the location property is the path of the external properties):

<context:property-placeholder location="classpath:jdbc.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"
>
<!--  Loading external properties file  -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
<!--  Use spring Expression acquisition properties Value in file  -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

</beans>

Test Code

    /**
     * Generating a c3p0 data source from a spring container
     */
    @Test
    public void testSpringCreateDataSource() throws SQLException {
        ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource)application.getBean("dataSource");
//        DataSource dataSource = application.getBean(DataSource.class);
        Connection connection = dataSource.getConnection();
        System.out.println("adopt spring Container acquired connection:"+connection);
        connection.close();
    }
    /**
     * Generating Druid Data Source from spring Container
     */
    @Test
    public void testSpringCreateDruidDataSource() throws SQLException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        DruidDataSource druidDataSource = (DruidDataSource)applicationContext.getBean("druidDataSource");
        DruidPooledConnection connection = druidDataSource.getConnection();
        System.out.println("adopt Spring Container acquired connection"+connection);
        connection.close();
    }

2 Spring Annotation Development

2.1 Quick Start Notes

Reduce my configuration and improve development efficiency with the following original comments

Case study: Replace xml configuration with Component and Autowired Qualifier

spring Core Profile:

<!--    Configure Component Scan    -->
<context:component-scan base-package="com.raphuscucullatus"/>

Dao Layer

package com.raphuscucullatus.dao.impl;

import com.raphuscucullatus.dao.UserDao;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author raphus cucullatus
 * @version 2021/9/17 18:25
 * @since JDK8
 */
@Component("userDao")//Equivalent to <bean id="userDao" class="com.raphuscucullatus.dao.impl.UserDaoImpl"/>
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("save running....");
    }
}

Service Layer

package com.raphuscucullatus.service.impl;

import com.raphuscucullatus.dao.UserDao;
import com.raphuscucullatus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * UserService Implementation Class
 *
 * @author raphus cucullatus
 * @version 2021/9/17 20:42
 * @since JDK8
 */
@Component("userService")//Equivalent to <bean id="userService" class="com.raphuscucullatus.service.impl.UserServiceImpl"/>
public class UserServiceImpl implements UserService {

    /**
     * set injection
     * @param userDao
     */
    @Autowired
    @Qualifier("userDao")//Equivalent to set injection <property name="userDao" ref="userDao"/>
    private UserDao userDao;
    public void setUserDao(UserDao userDao){
        this.userDao=userDao;
    }
    @Override
    public void save() {
        userDao.save();
    }
}

test

package com.raphuscucullatus.controller;

import com.raphuscucullatus.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * Simulate test cases for the control layer
 *
 * @author raphus cucullatus
 * @version 2021/9/17 20:51
 * @since JDK8
 */
public class UserControllerTest {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = app.getBean(UserService.class);
        userService.save();

    }
}

2.2 Detailed original notes

Core Profile

**Note: ** You need to use the context namespace (added in the properties of the beans tag)

<?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"
>
	<!--  Loading external properties file  -->
    <context:property-placeholder location="jdbc.properties"/>

    <!--    Configure Component Scan(Do not configure package scanning,spring Classes that need to be injected will not be recruited)    -->
    <context:component-scan base-package="com.raphuscucullatus"/>

</beans>

Using annotations in the dao layer

package com.raphuscucullatus.dao.impl;

import com.raphuscucullatus.dao.UserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
 * @author raphus cucullatus
 * @version 2021/9/17 18:25
 * @since JDK8
 */
//@Component("userDao")//Equivalent to <bean id="userDao" class="com.raphuscucullatus.dao.impl.UserDaoImpl"/>
@Repository("userDao")//Equivalent to @Component("userDao") and indicates that the class is a dao layer class
public class UserDaoImpl implements UserDao {
    
    /**
     * User name
     */
    //Same as <property name="user" value="${jdbc.user name}"></property>
    @Value("${jdbc.username}")//Read the value of the external properties file through the annotation configuration
    private String userName;
    /**
     * Password
     */
    //Same as <property name="password" value="${jdbc.password}"></property>
    @Value("${jdbc.password}")//Read the value of the external properties file through the annotation configuration
    private String password;
	
    @PostConstruct//Execute the send method after executing the constructor (Understanding)
    public void init (){
        System.out.println("UserDaoImpl Initialization");
    }
    
    @PreDestroy//Execute before destroying containers (Understanding)
    public void destroy (){
        System.out.println("UserDaoImpl Destroyed");
    }

    @Override
    public void save() {
        System.out.println("User name:"+userName+",Password:"+password);
        System.out.println("save running....");

    }
}

Using annotations in the service layer

package com.raphuscucullatus.service.impl;

import com.raphuscucullatus.dao.UserDao;
import com.raphuscucullatus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


/**
 * UserService Implementation Class
 *
 * @author raphus cucullatus
 * @version 2021/9/17 20:42
 * @since JDK8
 */
//@Component("userService")//Equivalent to <bean id="userService" class="com.raphuscucullatus.service.impl.UserServiceImpl"/>
@Service("userService")//Equivalent to @Component("userService") at service level
@Scope("singleton")
public class UserServiceImpl implements UserService {
    /**
     * set injection
     * @param userDao
     */
//    When @Autowired//does not use the @Qualifier("userDao") annotation, the default matching data type (.class) is injected, and the @Qualifier("userDao") annotation must be used if there are multiple types of the same type in the container
//    @Qualifier("userDao")// Equivalent to set injection <property name="userDao" ref="userDao"/>, @Qualifier must be used with @Autowired
    @Resource(name="userDao")//Equivalent to @Qualifier+@Autowired
    private UserDao userDao;
    //This set method may not be defined when using annotation configuration
//    public void setUserDao(UserDao userDao){
//        this.userDao=userDao;
//    }

    @Override
    public void save() {
        userDao.save();
    }
}

Simulate test cases for the control layer

package com.raphuscucullatus.controller;

import com.raphuscucullatus.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import java.awt.peer.ScrollPanePeer;

/**
 * Simulate test cases for the control layer
 *
 * @author raphus cucullatus
 * @version 2021/9/17 20:51
 * @since JDK8
 */
public class UserControllerTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = app.getBean(UserService.class);
        userService.save();
        app.close();

    }
}

2.3 New Notes Detailed

Solve the original annotation problem

The xml configuration file cannot be completely replaced, and the following configuration needs to be replaced by annotations:

  • Configuration of non-custom beans:
  • Load the configuration of the properties file: context:property-placeholder
  • Configuration for component scanning: context:component-scan
  • Introduce additional core profile files:
<?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"
>
	<!--    Non-Custom Bean Configuration    -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <property name="driverClass" value="${jdbc.driver}"></property>
       <property name="jdbcUrl" value="${jdbc.url}"></property>
       <property name="user" value="${jdbc.username}"></property>
       <property name="password" value="${jdbc.password}"></property>
    </bean>
	<!--  Loading external properties file  -->
    <context:property-placeholder location="jdbc.properties"/>

    <!--    Configure Component Scan(Do not configure package scanning,spring Classes that need to be injected will not be recruited)    -->
    <context:component-scan base-package="com.raphuscucullatus"/>
    
    <!--    Introducing external profiles    -->
	<import resource="applicationContext-user.xml"/>

</beans>


Core Configuration Class

Do not introduce external configuration

package com.raphuscucullatus.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;

import javax.sql.DataSource;

/**
 * spring Core Configuration Class
 *
 * @author raphus cucullatus
 * @version 2021/9/18 23:10
 * @since JDK8
 */
@Configuration//Tell Spring configuration information to look into this class (that is, use this class instead of the configuration file)
@ComponentScan("com.raphuscucullatus")//Same: <context:component-scan base-package="com.raphuscucullatus"/>
@PropertySource("jdbc.properties")//Same: <context:property-placeholder location="jdbc.properties"/>
//@Import({DataSourceConfiguration.class})//Same: <import resource="applicationContext-user.xml"/>
public class SpringConfiguration {

    @Value("${jdbc.url}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;
    @Bean("dataSource")

//    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
//       <property name="driverClass" value="${jdbc.driver}"></property>
//       <property name="jdbcUrl" value="${jdbc.url}"></property>
//       <property name="user" value="${jdbc.username}"></property>
//       <property name="password" value="${jdbc.password}"></property>
//    </bean>
//    For non-custom classes, the @Component("dataSource") annotation cannot be added to their source code, the solution is as follows: @Bean()
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }

}

Introducing external configuration

package com.raphuscucullatus.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;

/**
 * spring Core Configuration Class
 *
 * @author raphus cucullatus
 * @version 2021/9/18 23:10
 * @since JDK8
 */
@Configuration//Tell Spring configuration information to look into this class (that is, use this class instead of the configuration file)
@ComponentScan("com.raphuscucullatus")//Same: <context:component-scan base-package="com.raphuscucullatus"/>
@PropertySource("jdbc.properties")//Same: <context:property-placeholder location="jdbc.properties"/>
@Import({DataSourceConfiguration.class})//<import resource="applicationContext-user.xml"/>
public class SpringConfiguration {
}
package com.raphuscucullatus.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;

/**
 * Data Source Configuration Class
 * @author raphus cucullatus
 * @version 2021/9/18 23:46
 * @since JDK8
 */
public class DataSourceConfiguration {
    @Value("${jdbc.url}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;
    @Bean("dataSource")
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }
}

This test class can be tested in both ways

/**
 * Generating Druid Data Sources by Configuring spring Containers with Annotations
 */
@Test
public void testAnnotationCreateDruidDataSource() throws SQLException {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    DruidDataSource druidDataSource = (DruidDataSource)applicationContext.getBean("dataSource");
    DruidPooledConnection connection = druidDataSource.getConnection();
    System.out.println("adopt Spring Container acquired connection"+connection);
    connection.close();
}

3 Spring Integrated Junit

Spring Integrated Junit Step

1. Import Dependency

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

(2) Replace the original run time with the **@Runwith comment
(3) Use @ContextConfiguration to specify profiles or configuration classes
(4) Use @Autowired** to inject objects that need to be tested
Create test methods for testing

package com.raphuscucullatus.test;

import com.raphuscucullatus.config.SpringConfiguration;
import com.raphuscucullatus.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.sql.DataSource;
import java.sql.SQLException;


/**
 * spring Integrated junit test cases
 *
 * @author raphus cucullatus
 * @version 2021/9/19 0:26
 * @since JDK8
 */
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:applicationContext.xml")
@ContextConfiguration(classes = {SpringConfiguration.class})
public class TestUtil {
    @Autowired
    private UserService userService;
    @Autowired
    private DataSource dataSource;

    @Test
    public void test(){
//        userService.save();
        try {
            System.out.println(dataSource.getConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Tags: Java Spring

Posted on Sat, 18 Sep 2021 15:23:24 -0400 by shank888