1. 控制反转(IOC)和依赖注入(DI)介绍

控制反转(Inversion of Control,IoC)是一个比较抽象的概念,是Spring框架的核心,用来消减计算机程序的耦合问题
依赖注入(Dependency Injection,DI)是IoC的另外一种说法,只是从不同的角度,描述相同的概念。

1.1 控制反转IOC(基于反射)

控制反转是一种通过描述(在Spring中可以是XML或注解)并通过第三方去产生或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入。(简单说,就是把创建对象和管理对象的权利交给spring)

  • 就是把原来new对象的这种方式转换成了由spring通过反射技术(通过class)创建对象的方式。
  • spring创建完的对象放到一个容器中,谁需要就给谁注入进去 - (获取对象并赋值给引用)
  • new ClassPathXmlApplicationContext(“applicationContext.xml”);获取核心配置。

1.2 依赖注入DI(赋值基于set方法)

依赖注入是Spring容器将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例。(本质上就是给对象的属性赋值(set方法),对对象的属性进行赋值
  可以通过bean的property标签进行对对象的赋值。(property标签就是调set方法**)**
   property对象的赋值就是调用对象的set方法设置属性。如果让Spring容器管理set赋值,对象一定要有对应的set方法,且名称一致。
property标签,找的是类的属性对应的set方法,本质调set方法,如果对应属性对应set方法不存在,就会报红,找不到

在这里插入图片描述


2. SpringIOC

  Spring IoC容器的设计主要是基于BeanFactoryApplicationContext两个接口。我们一般就用第二种的ClassPathXmlApplicationContext

2.1 BeanFactory(通过绝对路径)

创建BeanFactory实例时,需要提供XML文件的**绝对路径。**
//创建BeanFactory 实例 -- 通过绝对路径
BeanFactory beanFactory = new XmlBeanFactory(
			new FileSystemResource("E:\\SSM\\Spring\\src\\com\\xgf\\ioc\\applicationContext.xml")

2.2 ApplicationContext的创建(通过类路径)【*****主要使用这种方式】

2.2.1 通过ClassPathXmlApplicationContext创建。

  ClassPathXmlApplicationContext将从类路径classPath目录(src根目录开始)寻找指定的XML配置文件。
【注意】在Spring中调用方法的名称和路径一定要和对应bean的路径和名称一致,因为IOC是通过反射,调用class文件来获取bean的,而项目有一个target文件夹,它的路径和方法名是和你需要调用的类的路径和方法名一致的。
在这里插入图片描述

//类路径
ApplicationContext context = 
	new ClassPathXmlApplicationContext("com/xgf/ioc/applicationContext.xml");
2.2.2 通过FileSystemXmlApplicationContext创建

  FileSystemXmlApplicationContext将从指定文件的绝对路径中寻找XML配置文件,找到并装载完成ApplicationContext的实例化工作

// 绝对路径 
ApplicationContext appCon = 
	new FileSystemXmlApplicationContext("E:\\SSM\\Spring\\src\\com\\xgf\\ioc\\applicationContext.xml");
TestDao tt = (TestDao)appCon.getBean("test");
2.2.3 通过Web服务器实例化ApplicationContext容器

Web服务器实例化ApplicationContext容器时,一般使用基于org.springframework.web.context.ContextLoaderListener的实现方式
此方法需要在web.xml中添加如下代码:

<context-param>
  	<!-- 加载src目录下的applicationContext.xml文件 -->
  	<param-name>contextConfigLocation</param-name>
  	<param-value>
  		classpath:applicationContext.xml
  	</param-value>
  </context-param>
  <!-- 指定以ContextLoaderListener方式启动Spring容器 -->
  <listener>
  	<listener-class>
  		org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>
2.3 scope属性,设置单例多例【**】

单例:内存中只有一个对象,每次获取到该对象的地址值一样。
多例:内存中的每个对象都是一个新的对象,他们的地址值都不同。调用就创建新对象。.

scope="singleton" 	单例(默认值,所以调用Spring创建对象默认都是同一个对象)
scope="prototype"	多例
scope="request" 	创建的对象放到request域中
scope="session" 	创建对象放到session对象


3. DI依赖注入类型

  Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(如属性值)注入Bean组件中

Spring框架的依赖注入通常有两种实现方式:

一种是构造方法注入,另一种是属性setter方法注入。

3.1 构造方法注入(constructor-arg)

  Spring框架采用Java的反射机制通过构造方法完成依赖注入
  constructor-arg给成员变量赋值(调用构造方法注入)

constructor-arg属性描述
name该属性对应bean的成员变量名
value该属性对应对应name的成员变量的值,可用于赋值

bean的constructor-arg 属性,调用bean对象的构造器进行赋值,赋值必须按照构造函数的参数赋值,不能少,用的地方很少。

<!-- 相当于User user =  new User(1,"jack",20,new Date()); 调用构造器赋值-->
    <bean id="date" class="java.util.Date"/>
    <bean id="user" class="com.xgf.bean.User" >
            <constructor-arg name="id" value="10"/>
            <constructor-arg name="name" value="hello"/>
            <constructor-arg name="age" value="20"/>
            <constructor-arg name="birthday" ref="date"/>
    </bean>

3.2 属性set方法注入【***】(常用)

  set方法注入是Spring框架中最主流的注入方式,它利用Java Bean规范所定义的set方法来完成注入,灵活且可读性高。set方法注入,Spring框架也是使用Java的反射机制实现的。

   通过bean的property标签- 给成员变量赋值(调用set方法注入)

property属性描述
name该属性对应bean的成员变量名
value该属性对应对应name的成员变量的值,可用于赋值

property调用set方法赋值

    <bean id="user" class="com.xgf.bean.User" >
    	<!-- 相当于user.setId(10) -->
        <property name="id" value="10"/>
        <!-- 相当于user.setName(rose) -->
        <property name="name" value="rose"/>
        <property name="age" value="20"/>
    </bean>

  property标签,找的是类的属性对应的set方法,在idea中,如果对应bean对应的set方法不存在,就会报红,提示找不到错误。(就是有对应的属性存在,但是没有对应属性的set方法,就不能通过property赋值)


4. 案例实现调用set方法注入,模拟IOC容器的注入(通过ClassPathXmlApplicationContext方式创建ApplicationContext)

步骤:
1.创建javabean类
2、创建Controller类将Controller托管给spring,让spring创建其对象
3.创建service接口实现类serviceImpl将serviceImpl托管给spring,让spring创建其对象
4、创建Dao接口实现类DaoImpl将DaoImpl托管给spring,让spring创建其对象
5、在Test中测试setter方法注入

简介需要用到的注解:

@Component  	//所有类上都可以使用
@Repository 	//Dao层用这个
@Service    	//Service层用这个
@Controller()	//Controller层用这个
//上面四个注解,是用来标识为bean对象,Spring容器扫描的时候能够识别加载
@Autowired		//自动装载,就是从Spring容器中找到类型相同的bean赋值给它
		// 比如 private UserService userService;
		//  相当于执行了实例化  private UserService userService = new UserServiceImpl();

环境准备:在pom.xml中引入spring的dependency

<!--spring 核心容器-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

4.1 创建测试类TestIOC

(Spring/src/main/java/com/xgf/ioc/Test/TestIOC.java)

/*
* 测试IOC依赖注入 - 通过setter方法注入
* */
public class TestIOC {
    public static void main(String[] args) {
        //注解进行配置,实例化ApplicationContext容器  通过ClassPathXmlApplicationContext方式实例化ApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("com/xgf/ioc/applicationContext.xml");

        //通过getBean方法从ApplicationContext容器当中获取User对象
        UserController userContrller = (UserController)context.getBean("userController");

        //调用User的name参数构造器测试
        userContrller.saveUser(new User("GF_浪夏一学"));

    }
}

4.2 创建User类(Spring/src/main/java/com/xgf/ioc/bean/User.java)

import java.util.HashMap;
import java.util.List;
import java.util.Set;

public class User {
    private String name;
    
    public User() {
        System.out.println("调用User的无参构造器");
    }
    public User(String name) {
        System.out.println("调用User的name参数构造器");
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

4.3 在resources下创建ApplicationContext.xml配置文件

(Spring/src/main/resources/com/xgf/ioc/applicationContext.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<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">

    <!--  配置注解扫描  扫描com.xgf.ioc下的所有文件 -->
    <context:component-scan base-package="com.xgf.ioc"/>
    <!-- 也可以单独配置bean,指定加入容器中的bean -->
    <!-- <bean id="user" class="com.xgf.bean.User"></bean> -->
</beans>

4.4 创建Controller

(Spring/src/main/java/com/xgf/ioc/controller/UserController.java)

/*
    @Controller注解  该注解用于标注一个控制器组件类
    容器一启动就会实例化  创建好之后以类名首字母小写放到容器中
    UserController 启动容器之后  创建好之后 变成---> key= userController value=new UserController();
* */
@Controller
public class UserController {
    /*
    @Autowired注解 按照类型进行匹配  - 自动装载
    该注解可以对类成员变量、方法及构造方法进行标注,完成自动装配的工作。
    通过 @Autowired的使用来消除setter 和getter方法。默认按照Bean的类型进行装配。
    */
    @Autowired
    private UserService userService;//  相当于执行了实例化  private UserService userService = new UserServiceImpl();

    //调用service的方法saveUser
    public void saveUser(User user){
        userService.saveUser(user);
    }
}

4.5. 创建Service

(Spring/src/main/java/com/xgf/ioc/service/UserService.java)

public interface UserService {
    void saveUser(User user);
}
/*
    @Service
	该注解用于标注一个业务逻辑组件类(Service层),其功能与@Component()相同。
    value是默认bean的id
    容器加载后会实例化,创建UserService对象
*/
@Service(value="userService")
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    @Override
    public void saveUser(User user) {
        userDao.saveUser(user);
    }
}

4.6 创建dao

(Spring/src/main/java/com/xgf/ioc/dao/UserDao.java)

public interface UserDao {
    void saveUser(User user);
}
/*
@Repository
	该注解用于将数据访问层(DAO)的类标识为Bean,即注解数据访问层Bean,其功能与@Component()相同。
	容器加载就会被实例化
*/
@Repository("userDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void saveUser(User user) {
        System.out.println("调用dao层userDao的saveUser方法,保存用户:"+user.getName());
    }
}

4.7 运行结果(实现注入成功)

在这里插入图片描述
通过创建User对象,调用Controller,通过spring的 @Autowired 注解自动装载service(通过类型找spring容器对应的bean),然后在service中自动装载dao,最后实现注入。@Autowired注解就相当于从Spring容器中通过类型,实例化了当前对象,可以直接调用它的方法。

@Autowired
private UserService userService;
//  相当于执行了实例化  private UserService userService = new UserServiceImpl();

关于注解,交给下一篇来解释啦哈哈哈。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐