Spring入门之IOC详解

本文介绍了Spring框架的核心——IOC(控制反转),详细阐述了Spring是什么、Spring的优势,以及Spring的体系结构。通过XML配置和注解开发的方式,逐步讲解了IOC的实现,包括bean的创建、依赖注入等。同时,提到了Spring的JdbcTemplate在持久层操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

众所周知,Spring 是目前市面上最主流的一款功能非常强大的框架,中文意思是春天,也让我们开发人员从JSP、sevlet的高耦合的开发中彻底的解救出来。废话少说,接下来就进行详细介绍。

【1】Spring是什么

Spring是一个开源框架,Spring的核心是控制反转(IOC)和面向切面(AOP)。

简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

轻量级:与EJB对比,依赖资源少,销毁的资源少。
分层: 一站式,每一个层都提供的解决方案

  • web层:struts2,spring-MVC
  • service层:spring
  • dao层:hibernate,mybatis , jdbcTemplate --> spring-data

【2】Spring优势

Spring 出现是为了解决JavaEE 实际问题:

  • 方便解耦,简化开发 (IOC)

    Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理

    Spring工厂是用于生成bean

  • AOP编程的支持

    ​ Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

  • 声明式事务的支持

    ​ 只需要通过配置就可以完成对事务的管理,而无需手动编程

  • 方便程序的测试

    ​ Spring对Junit4支持,可以通过注解方便的测试Spring程序

  • 方便集成各种优秀框架

    ​ Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

  • 降低JavaEE API的使用难度

    ​ Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

基于这些特性,我们也会俗称Spring为开发架构的粘合剂

【3】Spring体系结构

可以访问官网进行自主学习:https://spring.io/

Spring框架至今已集成了20多个模块,这些模块分布在以下模块中:

核心容器(Core Container)
数据访问/集成(Data Access/Integration)层
Web层
AOP(Aspect Oriented Programming)模块
植入(Instrumentation)模块
消息传输(Messaging)
测试(Test)模块

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhlRxQDj-1602776666517)(E:/Linux/%E6%A1%86%E6%9E%B6%E9%A2%84%E4%B9%A0%E8%B5%84%E6%96%99/%E6%A1%86%E6%9E%B6/spring-day01/01%E8%AE%B2%E4%B9%89/img/spring-framework.png)]

【4】Spring核心

  • 控制反转(Inversion of Control,IOC
  • 面向切面编程(aspect-oriented programming,AOP

Spring所有功能都依赖于这两个核心

注意:IOC和AOP并不是一种技术,而是一种思想,这点要清楚。

接下来就来讲一下IOC

【5】IOC

IOC介绍:IOC 全称为 Inversion of Control,翻译为 “控制反转”。

控制:控制对象的创建与销毁

反转:将对象的控制权(创建与销毁)交给Spring的IOC容器。

作用:解耦。

由于Java是面向对象开发,开发过程中由N个对象构成,各对象互相合作完成需求。但是此过程存在一个很大的问题,就是各个对象间耦合度太高,导致后期维护困难。

而Spring提供了一种IOC思想,就是引用“第三方”:IOC容器实现具有依赖关系的对象之间的解耦。全部对象的控制权都交给IOC容器,包括创建、销毁,这样各对象间就解除了关系,独立存在。

其他解释:

什么是ioc:控制反转,以前我们要获取对象,我们自己new.主动获取。现在有了工厂模式,我们需要获取对象,是工厂创建,我们被动接受工厂创建的对象.这就是控制反转.说白了ioc就是工厂模式. 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHa0c6JD-1602776666521)(C:\Users\Ali\AppData\Roaming\Typora\typora-user-images\1602219911489.png)]

spring框架提供了一个大工厂接口:ApplicationContext(父接口Beanfactroy)

spring-IOC的配置采取的是什么类型?

spring使用XML格式的文件存储配置
	<bean id="唯一标识" 
          class="实现类的全限定名">
	</bean>

spring-IOC是怎么加载配置文件的呢?

ApplicationContext工厂使用ClassPathXmlApplicationContext加载配置文件

基于多个实现类需要进行功能切换,我们只需要修改配置文件,不需要改java代码,所以不需要重新编译。

【6】IOC的XML开发

使用一个入门小案例来讲解

使用ApplicationContext:spring-IOC容器创建对象

1.配置pom.xml,引入spring-context依赖

<?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.vv.spring</groupId>
  <artifactId>spring-ioc</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>spring-ioc</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>
    
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- spring版本 -->
    <spring.version>5.1.11.RELEASE</spring.version>
  </properties>

  <dependencies>
      <!--spring ioc依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
       <!-- junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
  </dependencies>
  <build>
        <plugins>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

2.编写配置文件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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--bean
        作用:
            声明类交给spring容器
        属性:
            id: 唯一标识
            class:全路径限定名称
        细节:
            默认使用无参构造函数实例化-->
<bean id="accountDao" class="com.vv.spring.dao.Impl.AccountDaoImpl"/>
<bean id="accountService" class="com.vv.spring.service.Impl.AccountServiceImpl"/>
</beans>

3.通过spring的工厂获取对象

public class SpringTest {
    public static void main(String[] args) {
        //1.创建spring的工厂
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //2.通过spring的工厂获取对象
        Object userService = ac.getBean("userService");
        System.out.println(userService);
    }
}

bean标签详解

<?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 definitions here -->
    <!--
        bean标签:  创建对象,将对象装配到spring容器(泛指spring工厂类)。
            id: 对象的唯一标识
            class:实现类的路径,底层就是通过反射机制创建对象的。
            init-method:  对象创建时,要调用的初始化方法
            destroy-method:  对象销毁时,要调用的销毁方法
            scope:用来配置bean的作用域
                singleton: 单例(默认)
                prototype: 多例
            对象的生命周期:
                applicationContext: 工厂初始化时,对象就创建完毕。(单例情况下)
                单例:
                    工厂初始化时创建对象。
                    只要工厂存在,对象就存在。
                    工厂销毁,对象销毁。
                多例:
                    什么时候用,什么时候创建。
                    工厂存在,对象存在。
                    工厂销毁,对象不销毁。对象只能等待垃圾回收机制回收。
    -->
    <bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.itheima.service.impl.UserServiceImpl"></bean>
</beans>

UserServiceImpl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMjihyQf-1602776666524)(C:\Users\Ali\AppData\Roaming\Typora\typora-user-images\1602768687884.png)]

Test

public class SpringTest {
    public static void main(String[] args) {
        System.out.println("************工厂初始化start***********");
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        System.out.println("************工厂初始化end*************");
        //通过spring的工厂获取对象
        Object userService = ac.getBean("userService");
        Object userService2 = ac.getBean("userService");
        System.out.println(userService);
        System.out.println(userService2);
        //销毁工厂
        System.out.println("*************销毁工厂*****************");
        ac.close();
    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1hCV6HR-1602776666527)(C:\Users\Ali\AppData\Roaming\Typora\typora-user-images\1602768484976.png)]

创建对象的4种方式

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


    <!--
        spring创建对象的4种方式
            1.默认 无参构造
            2.工厂类的静态方法
            3.工厂类的动态方法
            4.BeanFactory接口方式,后面ssm整合再去介绍
    -->
    <!-- 默认无参构造方式-->
    <bean id="userService" class="com.vv.service.impl.UserServiceImpl"></bean>

    <!-- 工厂类的静态方式 -->
    <bean id="userService2" class="com.vv.utils.BeanFactory" factory-method="getUserService"></bean>

    <!-- 工厂类的动态方法-->
    <bean id="factoryBean2" class="com.vv.utils.BeanFactory2"></bean>
    <bean id="userService3" factory-bean="factoryBean2" factory-method="getUserService" ></bean>
</beans>
public class UserServiceImpl implements UserService {
    //无参构造
    public UserServiceImpl() {
        System.out.println("UserServiceImpl的无参构造被调用了");
    }
}
public class BeanFactory {
	//工厂类的静态方法
    public static UserService getUserService(){
        System.out.println("工厂类的静态方法");
        return new UserServiceImpl();
    }
}
public class BeanFactory2 {
	//工厂类的动态方法
    public  UserService getUserService(){
        System.out.println("工厂类的动态方法");
        return new UserServiceImpl();
    }
}

【7】spring的依赖注入DI

Dependency Injection (依赖注入):

spring创建对象的时候,给对象的属性赋值,就是依赖注入。

注意是spring创建对象!!!

方式一:有参构造

applicationContext.xml

    <!-- 有参构造方式-->
    <bean id="userService" class="com.vv.service.impl.UserServiceImpl">
        <!--
            给哪个属性赋什么值
            确定属性
                name: 通过属性名确定属性
				index: 通过索引来确定属性
                type: 通过属性的类型确定属性
            赋值:
                value:基本类型的赋值
                ref: 引用型类型的赋值
        -->
        <constructor-arg name="age" value="23"  ></constructor-arg>
        <constructor-arg name="game" value="LOL"></constructor-arg>
        <constructor-arg name="username" value="张三"></constructor-arg>
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>

    <!-- 有参构造方式-->
    <bean id="userService2" class="com.vv.service.impl.UserServiceImpl">
        <constructor-arg index="1" value="23"  ></constructor-arg>
        <constructor-arg index="2" value="LOL"></constructor-arg>
        <constructor-arg index="0" value="张四"></constructor-arg>
        <constructor-arg index="3" ref="userDao"></constructor-arg>
    </bean>

    <!-- 有参构造方式-->
    <bean id="userService3" class="com.vv.service.impl.UserServiceImpl">
        <constructor-arg type="java.lang.Integer" value="23"  ></constructor-arg>
        <constructor-arg type="java.lang.String" value="王五"></constructor-arg>
        <constructor-arg type="java.lang.String" value="LOL"></constructor-arg>
        <constructor-arg type="com.vv.dao.UserDao" ref="userDao"></constructor-arg>
    </bean>

UserServiceImpl

public class UserServiceImpl implements UserService {
    private String username;
    private Integer age;
    private String game;
    private UserDao userDao;
    //有参构造
    public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
        this.username = username;
        this.age = age;
        this.game = game;
        this.userDao = userDao;
    }
    public UserServiceImpl() {
    }
    @Override
    public void login() {
        userDao.findUserByUser();
    }
}

Test

public class SpringTest {
    //这是一个servlet
    public static void main(String[] args) {
        //调用service的方法
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        UserService userService = (UserService)ac.getBean("userService");
        userService.login();
    }
}

方式二:set方法

applicationContext.xml

 <!-- 属性的set方法 -->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl">
    <!--
        name:用来确定属性的。
            name属性的值是set的方法名去掉set后的驼峰命名名字。
        value:基本类型的属性赋值
        ref:引用型类型的属性赋值
    -->
    <property name="username" value="赵六"></property>
    <property name="age" value="25"></property>
    <property name="game" value="王者荣耀"></property>
    <property name="userDao" ref="userDao"></property>
</bean>

UserServiceImpl

public class UserServiceImpl implements UserService {
    private String username;
    private Integer age;
    private String game;
    private UserDao userDao;
    public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
        this.username = username;
        this.age = age;
        this.game = game;
        this.userDao = userDao;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void setGame(String game) {
        this.game = game;
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public UserServiceImpl() {
    }
    @Override
    public void login() {
        userDao.findUserByUser();
    }
}

Test

public class SpringTest {
    //这是一个servlet
    public static void main(String[] args) {
        //调用service的方法
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        UserService userService = (UserService)ac.getBean("userService");
        userService.login();
    }
}

使用名称空间简写依赖注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SY5FQHt-1602776666530)(C:\Users\Ali\AppData\Roaming\Typora\typora-user-images\1602772655928.png)]

注入复杂类型的依赖

UserServiceImpl

public class UserServiceImpl2 implements UserService {
    private String[] gameNames;
    private List<String> dogType;
    private Set<String> catType;
    private Map<String,String> map;
    public void setGameNames(String[] gameNames) {
        this.gameNames = gameNames;
    }
    public void setDogType(List<String> dogType) {
        this.dogType = dogType;
    }
    public void setCatType(Set<String> catType) {
        this.catType = catType;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    @Override
    public void login(){
    }
}

applicationContext.xml

<!--复杂类型的注入-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl2">
    <property name="gameNames">
        <array>
            <value>LOL</value>
            <value>PUBG</value>
            <value>王者荣耀</value>
        </array>
    </property>
    <property name="dogType">
        <list>
            <value>博美</value>
            <value>柴犬</value>
            <value>哈士奇</value>
        </list>
    </property>
    <property name="catType">
        <set>
            <value>英短</value>
            <value>橘猫</value>
            <value>无毛猫</value>
        </set>
    </property>
    <property name="map">
       <map>
           <entry value="科比" key="name"></entry>
       </map>
    </property
</bean>

【8】JdbcTemplate

Spring提供的JdbcTemplatemybatis框架一样,都是对jdbc的封装,用于支撑持久层的操作,但企业开发中mybatis应用较广。

下面就对JdbcTemplate的用法进行简单介绍。

步骤:

1、搭建数据库环境;
2、创建工程导入依赖

<dependencies>
    <!-- spring的jdbcTemplate相关,注意,spring技术的所有版本要保证统一-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.6.RELEASE</version>
    </dependency>
    <!-- junit单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- spring的ioc相关-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.6.RELEASE</version>
    </dependency>
    <!-- mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>
</dependencies>

3、创建pojo层
4、实现dao层接口和实现类
5、实现service层接口和实现类
6、通过配置文件实现IOC和依赖注入

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

    <!--accountService-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <!--注入accountDao-->
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--accountDao-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <!--依赖注入jdbcTemplate-->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!--jdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--依赖注入数据源-->
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>

    <!--创建数据源对象-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- set方法依赖注入-->
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/itheima115_spring_day02"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
</beans>

7、创建测试用例完成测试
8、优化-加载外部数据源

pom.xml

<!--德鲁伊连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.9</version>
</dependency>
<!-- c3p0-->
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<!--dbcp-->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

applicationContext.xml

<!--德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <!-- set方法依赖注入-->
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    <property name="url" value="${jdbc.url}"></property>
    <property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>

<!--c3p0-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- set方法依赖注入-->
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
    </bean>

<!--dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <!-- set方法依赖注入-->
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    <property name="url" value="${jdbc.url}"></property>
    <property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>

【9】IOC的注解开发

注解开发的优点:提高开发效率。

主要分为下面几个类型使用:

创建对象:@component; @Controller; @Service; @Repository;
依赖注入:@Autowired; @Qualifier; @Resource(name=beanid); @Value;
生命周期:@Scope; @PostConstruct; @PreDestroy;
纯注解开发相关:@Configuration; @ComponentScan; @PropertySource; @Import; @Bean
Spring整合单元测试:@RunWith; @ContextConfiguration;

具体的使用方法还没来得及总结,有空发出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值