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博客

相关推荐
南宫生3 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石11 分钟前
12/21java基础
java
李小白6619 分钟前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp32 分钟前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶1 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
n北斗1 小时前
常用类晨考day15
java
骇客野人1 小时前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言
AskHarries2 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
yuanbenshidiaos2 小时前
c++---------数据类型
java·jvm·c++
向宇it2 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎