spring_ioc,DI

ioc简介:

什么是IOC呢?

IOC(Inversion of Control),中文意思就是控制反转,ioc并不是一种特定的编程语言,指的是一种编程思想,指的是将创建对象的操作权限交给容器(这里指的是spring容器),通过容器来创建对象和管理对象,简单来说就是将原先的控制权由程序本身转给容器(本篇主要指的是spring)

 依赖注入

依赖注入(Dependency Injection):依赖注入指的是在程序的运行过程中,当程序需要调用另一个对象协助时,不用在代码中创建对象并进行调用,而是将创建过程与调用过程交给外部的容器来管理(spring),由外部容器创建后传递给层序

为什么会有依赖注入的存在?

一个稍微复杂一点的程序,其组成的类基本都是两个或两个以上了,这些类组成应用程序完成相关的业务逻辑。每个对象负责管理与自己相互协作的对象的引用,一个对象可能会引用多个对象,这就会导致高度的耦合和代码的难以测试,编码的基本准则是“低耦合,高内聚”

耦合具有两面性:

1:紧密的耦合会导致代码难以测试,难以复用,难以理解

2:一个程序要想完成特定的功能,一定程度的耦合又是必须的,不同的类之间必须进行一定的交互

依赖注入:通过依赖注入,对象的依赖关系将由负责协调系统中各个对象的第三方组件在创建对象时设定,对象无需自行创建或管理它们之间的依赖关系,也就是依赖关系将被注入到它们的依赖关系中去

实现依赖注入的两种方式

# 基于xml配置文件的依赖注入

setter方法

以下的例子相当于在一个类中使用另一个类中的方法

1:创建一个UserDao接口

package com.doaoao.dao;
public interface UserDao {
    void addUser();
}

2:创建UserDao接口的实现类

package com.doaoao.impl;
import com.doaoao.dao.UserDao;
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }
}

3:创建UserService接口

package com.doaoao.dao;
public interface UserService {
    void addUser();
}

4:创建UserService的实现类(在Service中使用UserDao)

package com.doaoao.impl;

import com.doaoao.dao.UserDao;
import com.doaoao.dao.UserService;

public class UserServiceImpl implements UserService {

    private UserDao userDao;
    @Override
    public void addUser() {
        // 注:之前如果想使用UserDao的对象时,必须先创建该对象,如下
        // UserDao userDao = new UserDaoImpl()

        // 使用spring 由spring为我们创建对象
        userDao.addUser();  // 调用UserDaoImpl中的实现方法
    }
  

  // 要给UserDao添加getter和setter方法
public UserDao getUserDao() { return userDao; } // spring容器在实现依赖注入时会调用set方法,将userDao对象注入给当前对象,也就是UserServiceImpl类的对象
  public void setUserDao(UserDao userDao) { this.userDao = userDao; } }

5:修改配置文件中的内容(当Spring读取配置文件时,会将userDao注入到对应的类中)

<bean id="userService" class="com.doaoao.impl.UserServiceImpl">
    <property name="userDao" ref="userDaoId" />  
  
<!-- ref的值为下方bean的id值 userDao与 private UserDao userDao中的userDao命名得一致-->
</bean> <bean id="userDaoId" class="com.doaoao.impl.UserDaoImpl" />

6:添加测试类

    @Test
    public void Test02(){
        // 读取spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从配置文件中获取对应id所对应的对象
        UserService userService = (UserService) context.getBean("userService");

        userService.addUser();
    }

# 使用spring的依赖注入之后,spring容器会帮我们创建UserDaoImpl的对象,并通过setter方法注入到UserService中的userDao属性上面

## 构造注入(容器通过构造方法将实例化的对象进行注入)

1:修改之前的UserServiceImpl,添加有参构造方法

package com.doaoao.impl;
import com.doaoao.dao.UserDao;
import com.doaoao.dao.UserService;
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    @Override
    public void addUser() {
        // 注:之前如果想使用UserDao的对象时,必须先创建该对象,如下
        // UserDao userDao = new UserDaoImpl()

        // 使用spring 由spring为我们创建对象
        userDao.addUser();  // 调用UserDaoImpl中的实现方法
    }
    // 构造注入
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}

 2:修改配置文件

<bean id="userService" class="com.doaoao.impl.UserServiceImpl">
    <constructor-arg name="userDao" ref="userDaoId" />
</bean>
<bean id="userDaoId" class="com.doaoao.impl.UserDaoImpl" />
<!-- userDao要与构造方法中的参数一致 UserDao userDao
userDaoId与下方的bean id要一致 -->

## 基于注解的依赖注入

  @Controller -----> springmvc中的controller

  @Repository ----> dao层

  @Service ---------> service层

  @Component --->可以代替上方三个

使用依赖注入,我们九不必再applicationContext.xml中注册bean

1:在配置文件中添加文件扫描器(使用注解就得先加上文件扫描器,扫描对应的类)

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 注册文件扫描器 -->
    <context:component-scan base-package="com.doaoao" /> 
</beans>

2:在类上使用注解 @Component,该注解中的参数用于指定该类的id

package com.doaoao.impl;
import com.doaoao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Component("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("执行了addUser");
    }
}

 在spring中提供类与@Component等效的注解

  @Repository 用于对 DAO 实现类进行注解
  @Service 用于对 Service 实现类进行注解
  @Controller 用于对 Controller 实现类进行注解

 例如在dao层的 UserDaoImpl 中使用 @Repository 注解

package com.doaoao.impl;
import com.doaoao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("执行了addUser");
    }
}

3:在service层的 UserServiceImpl 上使用 @Service

package com.doaoao.impl;
import com.doaoao.dao.UserDao;
import com.doaoao.dao.UserService;
import org.springframework.stereotype.Service;
@Service("userService")
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    @Override
    public void addUser() {// 使用spring 由spring为我们创建对象
        userDao.addUser();
    }

    // 构造注入
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}

4:创建测试方法(与之前相同)

    @Test
    public void Test02(){
        // 读取spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从配置文件中获取对应id所对应的对象
        UserService userService = (UserService) context.getBean("userService");

        userService.addUser();
    }

@Autowrite注解

加上该注解后,会按照类型进行装配,上面的示例中通过UserServiceImpl的构造方法对UserDao的注入,我们可以将这个构造方法省略,我们可以在private UserDao userDao上添加@Autowired注解,该注解默认使用按类型自动装配,即容器会查找UserDao类型的实例将其注入,spring容器会自动查找该对象

当使用@AUtowrite注解时,@Repository("userDao") 可以改写成 @Repository,因为默认是根据类型进行注入的,会自动找到该类型所对应的对象

我么可以对其进行修改,让其根据名称进行注入,还可以使用 @Qualifier注解让@Autowrite根据名称自动装配,

@Qualifier中的名称要跟UserDaoImpl类中@Repository("userDao")的名称一致,spring在查找对象时就会根据 userDao这个名字去查找

package com.doaoao.impl;

import com.doaoao.dao.UserDao;
import com.doaoao.dao.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    @Override
    public void addUser() {
        userDao.addUser(); 
    }

    // 无需构造方法
    // public UserServiceImpl(UserDao userDao) {
    //     this.userDao = userDao;
    // }
}

@Resource注解(该注解不是spring提供的,是java提供的注解)

该注解默认使用名字进行注解(来完成装配的/注入的)当我们下方没有写名字时,就是使用类型进行装配的(和 @Autowired)

可以按照名字进行装配 @Resource(name = “userDao”),当指定名字时,名字得和@Repository("userDao") 一样

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;
    
    @Override
    public void addUser() {
        userDao.addUser();
    }
}

下面另一种写法利用类型进行bean的注入

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource(type = "userDao")
    private UserDao userDao;
    
    @Override
    public void addUser() {
        userDao.addUser();
    }
}

两个区别:@Autowired是spring提供的,@Resource是java提供的,这两种注解在实际开发中二选一即可

@Autowired默认根据类型进行装配,@Resource默认使用名字进行装配

 // 使用注解实现初始化和销毁操作

@PostConstruct
public void before() {
    System.out.println("开始");
}

@PreDestroy
public void after() {
    System.out.println("结束");
}

 利用注解@Scope指定bean的作用域,默认的作用域为 singleton 单例模式

@Scope("prototype")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("执行了方法 UserDaoImpl");
    }
}

## 注解和xml配置的利弊

注解的好处是,配置方便,直观。但其弊端也显而易见:以硬编码的方式写入到了 Java代码中,其修改是需要重新编译代码的。

XML 配置方式的最大好处是,对其所做修改,无需编译代码,只需重启服务器即可将新的配置加载。

若注解与 XML 同用,XML 的优先级要高于注解。这样做的好处是,需要对某个 Bean 做修改,只需修改配置文件即可。当然,此时,Bean 类要有 setter 或构造器。

## 如何添加多个配置文件

随着系统中的Bean的数量增加,会导致配置温江变得及其的臃肿,会导致可维护性的降低,为了避免这种事情的发生,可以将Spring配置文件分解成多个配置文件

# 添加多个配置文件-方式1

// 在resource目录下创建多个配置文件
spring-app.xml
spring-bean.xml


// 在测试方法中:将配置文件的文件名写道数组中,然后将该数组作为参数传入 ClassPathXmlApplicationContex
String[] files = {"spring-aop.xml","spring-bean.xml","applicationContext.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(files);

# 添加多个配置文件-方式2

选取一个主配置文件,例如选取 applicationContext.xml

在applicationContext.xml配置文件中加入如下的内容,这时就好比将 applicationContext.xml 配置文件变成一个父配置文件

<import resource="spring-aop.xml"/>
<import resource="spring-bean.xml"/>

<!-- 另一种写法,使用通配符的方式 -->
<!-- 当用通配符的方式写的时候,主配置文件不以 "spring作为开头" -->
<import rescorce="spring-*.xml">

 然后再测试代码中使用即可

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

...

本笔记参考自:小猴子老师教程 http://www.monkey1024.com

猜你喜欢

转载自www.cnblogs.com/Doaoao/p/10740366.html