likes
comments
collection
share

【Spring】浅谈下 Spring IoC 和 DI 以及 Spring 实操

作者站长头像
站长
· 阅读数 33

一、Spring

1. 为什么要使用Spring?

  • 解决代码耦合度高的问题

    以前的代码都是类似private IEmployeeDAO employeeDAO = new EmployeeDAOImpl();这样的代码,对象都是我们手动创建的,假如将实现类改成其它的,那就需要修改涉及到这个实现类的代码,这样大大增加了维护成本。(不符合开放-封闭原则)

  • 解决控制事务繁琐问题

    如果需要对某些业务方法进行事务管理,则需要写上开启事务、保存业务、提交事务、回滚事务等代码,假如有很多个业务方法都需要进行事务管理,则会造成大量重复代码,同时,维护上也很不方便。

  • 解决第三方框架运用太麻烦

    单纯使用MyBatis框架,则需要进行获取session对象、获取Mapper对象、执行相应SQL语句、提交事务、释放资源等,而对于使用者只关心使用的问题,而不在乎创建的问题。就比如我们需要使用手机打电话,我们关心的是直接使用手机,而不是自己造一部手机出来。

2. Spring是什么?

  • Spring是一种轻量级的 IoC、DI 和 AOP 容器的开源框架。
  • 简单地说,Spring可以帮我们创建以及管理配置好的对象设置对象的属性值,并将对象(单例)存到Spring容器中,而我们需要用的时候,直接从Spring容器取出来就可以使用。

3. Spring的优势

Spring 除了不能帮我们写业务逻辑,其余的几乎什么都能帮助我们简化开发,作用如下

  • Spring 能帮我们低侵入/低耦合地根据配置文件创建及组装对象之间的依赖关系。
  • Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制等。
  • Spring 能非常简单的且强大的声明式事务管理。
  • Spring 提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,且自己也提供了一套 JDBC 模板来方便数据库访问。
  • Spring 提供与第三方 Web(如 Struts1/2、JSF)框架无缝集成,且自己也提供了一套 Spring MVC 框架,来方便 Web 层搭建。
  • Spring 能方便的与如 Java Mail、任务调度、缓存框架等技术整合,降低开发难度。

4. Spring FrameWork体系

【Spring】浅谈下 Spring IoC 和 DI 以及 Spring 实操

5. Spring依赖

<!-- spring上下文依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.8.RELEASE</version>
</dependency>
<!-- spring测试依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.8.RELEASE</version>
    <scope>test</scope>
</dependency>

二、IoC 和 DI

1. IoC

  • Inversion of Control,控制反转
  • 将在程序中手动创建对象的控制权交给 IoC 容器,由 IoC 容器进行创建对象和管理对象

2. DI

  • Dependency Injection,依赖注入
  • 创建对象过程中,将对象依赖属性(常量、对象)通过配置设置值给该对象

IoC 和 DI都是一种思想或者称为想法,而Spring是这两种思想实现之一

三、Spring 基础知识

1. BeanFactory和ApplicationContext

【Spring】浅谈下 Spring IoC 和 DI 以及 Spring 实操

2. Spring 配置方式

  • XML-based configuration
  • Annotation-based configuration
  • Java-based configuration

3. Spring IoC 管理 Bean 的原理

  • 通过Resource对象加载配置文件
  • 解析配置文件和Bean元素,将id作为bean的名字,class通过反射创建bean的实例 bean类必须存在一个无参构造器
  • 调用getBean()方法时,从容器中返回对象实例

4. XML基本配置

<context:property-placeholder location="classpath:db.properties"/>
<!--
        若类名字以 FactoryBean 结尾,需要注意具体创建什么类型的对象存到容器中
        初始化和销毁方法目前只有数据源对象才会配置
    -->
<bean id="唯一性" class="类全限定名" [init-method="初始化方法名" destroy-method="销毁方法名"]>
    <property name="属性名" value="属性值"|ref="容器中另外一个 bean 的 id 值"/>
    ......
</bean>
......

5. 实现 FactoryBean 接口实例化

Spring在对整个bean元素解析创建对象时,会先创建该工厂对象,但检测到这个类实现了FactoryBean接口,则会使用工厂对象调用getObject()方法创建bean对象,并把bean对象存入容器中。

集成 MyBatis 框架使用,就会配置 org.mybatis.spring.SqlSessionFactoryBean

6. Bean

  • bean的创建时机:启动 Spring 容器的时候创建所有的 bean

  • 作用域:singleton(默认)、prototype、request、session、application

  • 初始化和销毁:在配置文件中设置

    • 正常关闭容器,才会执行销毁方法

    • bean的scope为prototype时,容器只负责创建和初始化,不负责销毁。

      因为多例对象是一次性的,不需要进行保存,存放在spring容器外,如果存放在spring容器内,那么就会导致容器被这些对象占满

【Spring】浅谈下 Spring IoC 和 DI 以及 Spring 实操

四、第一个 Spring 程序

  1. 新建 Maven 项目并设置编译版本及添加依赖(pom.xml)

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>16</maven.compiler.source>
        <maven.compiler.target>16</maven.compiler.target>
    </properties>
    
    <dependencies>
            <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                    <version>1.1.9</version>
            </dependency>
            <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.45</version>
                    <scope>runtime</scope>
            </dependency>
            <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <version>1.18.20</version>
                    <scope>provided</scope>
            </dependency>
            <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                    <version>5.0.8.RELEASE</version>
            </dependency>
            <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-test</artifactId>
                    <version>5.0.8.RELEASE</version>
                    <scope>test</scope>
            </dependency>
            <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>4.12</version>
                    <scope>test</scope>
            </dependency>
    </dependencies>
    
  2. 创建表

    CREATE TABLE `employee` (
            `id` bigint(20) NOT NULL AUTO_INCREMENT,
            `username` varchar(255) DEFAULT NULL,
            `password` varchar(255) DEFAULT NULL,
            `age` int(11) DEFAULT NULL,
            PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  3. 编写数据库四要素(db.properties)

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql:///spring-demo
    jdbc.username=root
    jdbc.password=admin
    
  4. 编写 DAO 层代码

    public interface IEmployeeDAO {
        void save(String username, String password, age) throws Exception;
    }
    
    public class EmployeeDAOImpl implements IEmployeeDAO {
            private DataSource dataSource;
            public void setDataSource(DataSource dataSource) {
                    this.dataSource = dataSource;
            }
    
            @Override
            public void save(String username, String password, age) throws Exception {
                    @Cleanup
                    Connection connection = dataSource.getConnection();
                    @Cleanup
                    PreparedStatement ps = connection.prepareStatement("INSERT INTO employee(username, password, age) VALUES(?, ?, ?)");
                    ps.setString(1, username);
                    ps.setString(2, password);
                    ps.setInteger(3, age);
                    ps.executeUpdate();
            }
    }
    
  5. 编写业务层代码

    public interface IEmployeeService {
            void save(String username, String password, Integer age) throws Exception;
    }
    
    public class EmployeeServiceImpl implements IEmployeeService {
            private IEmployeeDAO employeeDAO;
            public void setemployeeDAO(IEmployeeDAO employeeDAO) {
                    this.employeeDAO = employeeDAO;
            }
    
            @Override
            public void save(String username, String password, age) throws Exception {
                    employeeDAO.save(username, password, age);
            }
    }
    
  6. 编写 Spring 配置文件(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"
           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="classpath:db.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean><bean id="employeeDAO" class="cn.regex.ims.dao.impl.EmployeeDAOImpl">
            <property name="dataSource" ref="dataSource"/>
        </bean><bean id="employeeService" class="cn.regex.ims.service.impl.EmployeeServiceImpl">
            <property name="employeeDAO" ref="employeeDAO"/>
        </bean>
    </beans>
    
  7. 编写测试类(EmployeeServiceTest.java)

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class EmployeeServiceTest {
    ​
        @Autowired
        private IEmployeeService employeeService;
    ​
        @Test
        public void save() throws Exception {
            Employee employee = new Employee();
            employee.setUsername("regex");
            employee.setPassword("123456");
            employee.setAge(15);
            employeeService.save(employee);
        }
    }