JAVASpring

浅谈spring依赖注入

前言

先了解下控制反转转自知乎的国哥

如果一个类A 的功能实现需要借助于类B,那么就称类B是类A的依赖,如果在类A的内部去实例化类B,那么两者之间会出现较高的耦合,一旦类B出现了问题,类A也需要进行改造,如果这样的情况较多,每个类之间都有很多依赖,那么就会出现牵一发而动全身的情况,程序会极难维护,并且很容易出现问题。要解决这个问题,就要把A类对B类的控制权抽离出来,交给一个第三方去做,把控制权反转给第三方,就称作控制反转(IOC Inversion Of Control)。控制反转是一种思想,是能够解决问题的一种可能的结果,而依赖注入(Dependency Injection)就是其最典型的实现方法。由第三方(我们称作IOC容器)来控制依赖,把他通过构造函数、属性或者工厂模式等方法,注入到类A内,这样就极大程度的对类A和类B进行了解耦。

想理解控制反转,就得想清楚这个第三方,在spring中便是IOC容器。将原本两个耦合性很强的对象分给中介第三方进行控制。

依赖注入是实现控制反转的一种方式,依赖注入是将实例变量传入到一个对象中去的过程、方式、一种设计模式。依赖注入方式下,注入将依赖传给调用方,不是像原来的调用方直接使用依赖。所以很明显也是为了解耦,参考下wiki的图,了解大概分类:

Spring的依赖注入就是不需要像传统的方式来new你需要使用的对象,而是通过spring根据对象间的依赖关系,由容器来为你自动创建对象,实现了对象间的解耦。

Spring IOC创建对象和在new创建对象的区别

使用new

以业务层和持久层来举例,使用new时,在Servicce层需要引用dao层:

Public class ServiceImpl{

  Dao dao = new MysqlDaoImpl();

  dao.xx();

}

当项目想更换oracle数据库时,就需要改变serviceImpl层的代码为 new OracleDaoImpl(),需要改动代码,当引用此代码的类多,工作量会非常大。

Spring IOC 创建对象

springioc依赖注入,在serviceImpl类中创建Dao属性,在创建对象时可以使用set或者有参构造方法将dao注入进去。在spring创建Service对象时发现依赖了dao,会先去创建dao对象,此时dao的class里的是”com.dao.daoImpl.DaoImpl”,当service需要换数据库时,可以将class路径更改,实现解耦合。

Spring 通过注解依赖注入

在Spring IoC中主要提供了两个注解用于bean的创建和属性的注入,即@Component@Autowired

①这里@Component用在类声明上,用于告知Spring,比如当前创建的UserDaoImp类中,在后续的使用中,肯定是会需要UserDaoImp类的实例对象的,所以现在提供需要为当前UserDaoImp类创建一个实例(默认单例模式创建实例对象),实例名默认为当前类名首字母小写的形式,所以@Component就是在通知Spring你要预先给这个类实例化,所以接口与抽象类不能使用这个注解,因为他们没法实例化对象。

而@Autowired则用在属性上,Spring检测到该注解之后就会在IoC容器中查找是否有与该属性相匹配的类或子类实例,有的话就注入到当前属性中,否则就会报错。例如,在UserService类中:

    @Autowired  //根据类型进行注入
    private UserDaoImp userdaoImp;   //为了区分实例化对象,所以将这里将字母D改为小写

此时在userDaoImp属性上标@Autowired,意味着Spring在看到该属性后,会到IOC容器中寻找是否存在UserDaoImp类的实例化对象,上面说到通过@Component已经创建了一个实例userDaoImp,所以将此实例化对象赋值给userdaoImp,即:

UserDaoImp userdaoImp = userDaoImp;

这个赋值的过程就被称为属性的“注入”。

 UserDao接口:

    public interface UserDao {
        public void info();
    }

UserDaoImp实现类:

@Component
public class UserDaoImp implements UserDao {
    @Override
    public void info() {
        System.out.println("info()..............");
    }
}

UserService类:

//注解中value的默认值为UserService的首字母为小写,也就是userService
@Service(value = "userService") //此处等同于xml配置中的<bean id="userService",class="com.maweirdos.service.UserService"/>
public class UserService {
    @Autowired  //根据类型进行注入
    @Qualifier(value = "userDaoImp")    //根据name名称进行注入
    private UserDaoImp userDaoImp;
    public void Add(){
        System.out.println("add()..............");
        userDaoImp.info();
    }
}

测试类:

@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.Add();
    }

输出结果:

add()..............
info()..............