前言
如果一个类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()..............