Spring基础之——控制反转(IOC)、依赖注入(DI)与切面编程(AOP)概念详解(适合小白,初学者必看)

前言

本篇博客讲详细介绍Spring框架中的两个最核心且最基础的概念:控制反转(IOC)和面向切面编程(AOP)。以及如何通过IDEA来构建一个Spring项目,通过实战和理论结合的方式来让大家真的学会Spring这个最流行的Java框架。

一、认识Spring(是什么)

1. Spring框架的概述

Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

它是为了解决企业应用开发的复杂性而创建的。

Spring的核心是控制反转(IOC)和面向切面(AOP):

  • IOC:控制反转,将创建对象的过程交给spring进行管理.
  • AOP:面向切面,在不修改源代码的情况之下进行代码功能的增强.

2. Spring框架的优点

  • 方便解耦,简化开发,Spring就像一个大工厂,将所有对象的创建和依赖关系维护,交给Spring管理,这也是IOC的作用。
  • AOP编程的支持,Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
  • 声明式事务的支持,只需要通过配置就可以完成对事务的管理,而无需手动编程。
  • 方便程序的测试,Spring支持Junit4,可以通过注解方便的测试Spring程序。
  • 方便集成各种优秀框架,Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis等)的直接支持。
  • 降低JavaEE API的使用难度,Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。

二、Spring项目的创建

如今IDEA比较主流,下面我来演示如何使用IDEA来创建一个Spring项目。

1. 首先我们创建一个Maven工程

不知道如何创建Maven工程的小伙伴,请参考我的这篇博客:

Maven学习---如何在IDEA中配置Maven?又如何创建Maven工程?(详细攻略)_idea创建maven项目-CSDN博客

2. 引入Spring相关的依赖坐标

Spring框架基础依赖:

XML 复制代码
<dependencies>
<!--    Spring框架基础依赖    -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- 日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

AOP面相切面编程的依赖:

XML 复制代码
<!--  AOP面相切面编程的依赖 -->

        <!--AOP联盟-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!--Spring Aspects-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.3</version>
        </dependency>
3. 创建Spring核心的配置文件

在resources目录下创建applicationContext.xml的配置文件,名称是可以任意的,但是通常都使用默认名称。

给文件中的默认内容(有的小伙伴创建完可能是空的,我这里给出文件默认代码) :

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>

以上内容,就是一个最基础的Spring项目的创建方法。

三、Spring IOC容器

1. 什么是IOC

IOC (Inverse of Control),控制反转,将对象的创建权力交给给Spring框架去管理,实现控制权的反转。

2. IOC实现的底层原理

IOC的实现,依赖于以下3种技术

  • ① dom4j解析xml文档;
  • ② Java对象的一种创建方式:工厂模式;
  • ③ 采用Java中反射技术来创建对象

想要了解对底层原理深入了解的小伙伴,可以去Spring官网下载Spring底层源码。

Spring官方网站 Spring | HomeLevel up your Java code and explore what Spring can do for you.https://spring.io/

ioc底层有用到反射,面试时如果可以扯一扯Java基础反射相关的东西;

3、IOC的具体使用

常规情况下,类A中使用类C示意图:

当有了IoC/DI的容器后,A类不再主动去创建C了,

而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中,如下图所示:

有IoC/DI容器后程序结构示意图

  1. 控制反转(IOC):是从容器的角度出发,既:容器控制应用程序,由容器反向的向应用程序注入其所需要的外部资源。

  2. 依赖注入(DI):是从应用程序的角度在描述,既:应用程序依赖容器创建并注入它所需要的外部资源;

根据上面的讲述,应该能看出来,DI和IOC是对同一件事情的不同描述,从某个方面讲,他们就是同一概念,只是描述的角度不同。

当然对于我们初学者,我们首先去掌握spring IOC的使用方法即可;下面我来用基础代码为大家演示:Spring的控制反转和依赖注入两大设计理念的含义:

代码演示:

(1)通过IOC来创建Java类

①首先我先定义几个普通的Java类:

Teacher类:

User类:

通常情况下,我们若想要去创建这两个类的对象的话,会像下面这样:

  • 使用最普通New的方式
  • 使用反射的方式创建对象
java 复制代码
    public void createObjTest01() throws ClassNotFoundException {

        //1.使用最普通new的方式
        User user = new User();

        //2.使用反射的方式创建对象(需要在方法上抛出"找不到类"的异常)
        Class clazz = Class.forName("com.yzx.pojo.User");

    }

②但如果我们使用了Spring,我们创建对象的方式将发生改变,演示如下:

首先,在Spring的xml配置文件中进行bean注入:

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="user" class="com.yzx.pojo.User"></bean>
    <bean id="Teacher" class="com.yzx.pojo.Teacher"></bean>

</beans>
  • id 后面是你自定义该类的别名;
  • class 后面是你要托管给Spring管理的类的全路径;

然后,我们在test目录下创建一个测试类,来验证Spring是否已经可以管理这两个类。

测试类中的测试方法内容如下:

java 复制代码
@Test
    public void createObjTest02() throws ClassNotFoundException {
        //1.首先加Spring的载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.然后通过ApplicationContext的对象来获取所需对象
        User user = (User)ac.getBean("user");
        Teacher teacher = (Teacher)ac.getBean("teacher");

        usr.test();
        teacher.test();
    }

运行结果:

(2)通过IOC向类注入属性值

首先我们在Spring配置文件中为对象注入属性值

方法一: 使用<property>标签来实现对属性的注入,

复制代码
1.使用<property>标签来实现对属性的注入,使用该标签进行属性注入时,要求pojo类中必须配有setter方法,因此,该方法通常叫做使用setter方法注入

2.标签属性:
name:类中的属性名称
value:向属性注入的值
ref:对象映射

代码如下:

XML 复制代码
<bean id = "usr" class="com.yzx.pojo.User">

        <!--  ①配置基本类型的属性值   -->
        <property name="id" value="1"/>
        <property name="username" value="admin"/>
        <property name="password" value="123"/>
        <!--  ②配置数组类型的属性值   -->
        <property name="strs">
            <array>
                <value>admin</value>
                <value>张三</value>
                <value>李四</value>
            </array>
        </property>
        <!--  ③配置List集合类型的属性值   -->
        <property name="list">
            <list>
                <value>熊大</value>
                <value>熊二</value>
            </list>
        </property>
        <!--  ④配置map集合类型的属性值   -->
        <property name="map">
            <map>
                <entry key="aaa" value="小白"/>
                <entry key="bbb" value="小黑"/>
            </map>
        </property>
    </bean>

方法二: 使用<property>标签来实现对属性的注入,

复制代码
1.使用<constructor-arg>标签来实现对属性的注入,使用该标签进行属性注入时,要求pojo类中必须配有构造器,因此,该方法通常也叫做利用类的构造器注入。

2.标签属性:
name:类中的属性名称
value:向属性注入的值
ref:对象映射
XML 复制代码
<bean id="teacher" class="com.yzx.pojo.Teacher">
        <!--  ①配置基本类型的属性值   -->
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="tname" value="李老师"/>
        <!--  ②配置数组类型的属性值   -->
        <constructor-arg name="nums">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </array>
        </constructor-arg>
        <!--  ③配置List集合类型的属性值   -->
        <constructor-arg name="list">
            <list>
                <value>"你好"</value>
                <value>"spring"</value>
            </list>
        </constructor-arg>
        <!--  ④配置map集合类型的属性值   -->
        <constructor-arg name="map">
            <map>
                <entry key="张三" value="12"/>
                <entry key="李四" value="15"/>
            </map>
        </constructor-arg>
    </bean>

测试代码:

java 复制代码
@Test
    public void createObjTest02() throws ClassNotFoundException {
        //1.首先加Spring的载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.然后通过ApplicationContext的对象来获取所需对象
        User user = (User)ac.getBean("usr");

        Teacher teacher = (Teacher)ac.getBean("teacher");

        System.out.println(user.toString());
        System.out.println(teacher.toString());
    }

运行结果:

小结:

通过上述演示,相信大家对Spring框架中IOC和DI的概念有了基础的认识;

其实IoC/DI对编程带来的最大改变不是从代码上,而是从思想上,发生了"主从换位"的变化。应用程序原本具有最大的主动权,需要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC/DI容器来创建并注入应用程序所需要的资源了。

这样一个改变其实是编程思想的一个大进步,如此就可以有效的分离了对象和它所需要的外部资源,使得代码的耦合度降低,有利于代码复用,更重要的是使得程序的整个体系结构变得非常灵活。

四、Spring AOP面向切面编程

由于篇幅有限,AOP的具体内容请看小编下面的这篇博客

本文参考文献:

控制反转(IOC)和依赖注入(DI)的区别(详细 通俗易懂解释)_控制反转和依赖注入的理解(通俗易懂)-CSDN博客

相关推荐
编码者卢布几秒前
【Azure Storage Account】Azure Table Storage 跨区批量迁移方案
后端·python·flask
编码者卢布8 分钟前
【App Service】Java应用上传文件功能部署在App Service Windows上报错 413 Payload Too Large
java·开发语言·windows
q行43 分钟前
Spring概述(含单例设计模式和工厂设计模式)
java·spring
好好研究1 小时前
SpringBoot扩展SpringMVC
java·spring boot·spring·servlet·filter·listener
毕设源码-郭学长1 小时前
【开题答辩全过程】以 高校项目团队管理网站为例,包含答辩的问题和答案
java
NE_STOP2 小时前
spring6-工厂设计模式与bean的实例化方式
spring
玄〤2 小时前
Java 大数据量输入输出优化方案详解:从 Scanner 到手写快读(含漫画解析)
java·开发语言·笔记·算法
tb_first2 小时前
SSM速通3
java·jvm·spring boot·mybatis
独自破碎E2 小时前
总持续时间可被 60 整除的歌曲
java·开发语言