Spring的核心机制:依赖注入
依赖注入的概念
当一个对象要调用另一个对象时,一般是new一个被调用的对象,示例:
class a{
private b b=new b();
public void test(){
b.say();
}
}
a类的对象依赖于b类对象,如果没有b类对象,a类对象就不能正常工作,称a依赖于b。
以上方式会增加类a与类b的耦合性,不利于项目后期的升级(扩展)、维护。
在spring中,b类的实例(被调用者),不再由a类(调用者)创建,而是由spring容器创建,创建好以后,由spring容器将b类的实例注入a类对象中,称为依赖注入(dependency injection,di)。
原本是由a类主动创建b类对象(a类控制b类的创建),现在是spring容器创建b类对象,注入a类对象中,a类被动接受spring容器创建的b类实例,b类对象创建的控制权发生了反转,所以又叫做控制反转(inversion of control,ioc)。
依赖注入是一种优秀的解耦方式,由spring容器负责控制类(bean)之间的关系,降低了类之间的耦合。
因为spring容器负责依赖注入(ioc),所以spring容器也被称为spring ioc容器。
依赖注入有2种实现方式:
- 设值注入
- 构造注入
设值注入
通过主调类的setter()方法注入被调类的实例。一个参数即一个依赖对象。
1、分别写2个接口
1 public interface student { 2 public string getname(); 3 }
1 public interface teacher { 2 public void say(); 3 }
2、分别写2个实现类
1 public class badstudent implements student { 2 private string name; 3 4 public badstudent(string name){ 5 this.name=name; 6 } 7 8 @override 9 public string getname(){ 10 return name; 11 } 12 }
1 public class mathteacher implements teacher{ 2 private student student; 3 4 //主调者的setter()方法,接受被调者实例 5 public void setstudent(student student){ 6 this.student=student; 7 } 8 9 @override 10 public void say() { 11 system.out.println(student.getname()+",叫家长来一下。"); 12 } 13 }
类与接口耦合。
3、在applicationcontext.xml文件中配置bean
1 <!-- 初始化badstudent类的实例lisi--> 2 <bean name="lisi" class="beans.badstudent"> 3 <constructor-arg value="李四" /> <!--向badstudent的构造函数传递”李四“--> 4 </bean> 5 6 <!--配置依赖--> 7 <bean name="mathteacher" class="beans.mathteacher"> 8 <property name="student" ref="lisi" /> <!--name指定setter方法的形参,ref或者value指定实参:某个bean的name--> 9 </bean>
<constructor-arg>元素向该bean的构造函数传递实参,一个<constructor-arg>传递一个实参,一个<bean>可配置多个<constructor-arg>,根据传递的实参个数来调用相应的构造函数。constructor-arg即构造器参数。
实参值通过value或ref属性来指定。value指定的是java基础类型的参数,ref即reference(引用),指定依赖的其它bean。
可通过属性index指定该value是第几个参数,默认从0自动递增。
<property>属性指定setter方法的实参。一个<property>指定一个参数,一个<bean>可带有多个<property>子元素。
name属性指定setter方法中的某个形参,实参由value或ref指定。
如果实参是某个bean的实例,用ref指定,值是该bean的name属性值。
如果实参是java的基础类型(整型、浮点型、string等),用value指定(放在引号中),spring容器会自动根据name的指定形参的类型,将实参转换为相应的类型进行赋值。
4、写一个测试类
1 public class test { 2 public static void main(string[] args) { 3 classpathxmlapplicationcontext applicationcontext=new classpathxmlapplicationcontext("applicationcontext.xml"); 4 mathteacher mathteacher=applicationcontext.getbean("mathteacher",mathteacher.class); 5 mathteacher.say(); 6 } 7 }
看到控制台已经打印出了“李四,叫家长来一下。”。
构造注入
通过构造函数注入。
1、上面的代码,将mathteacher类修改如下
1 public class mathteacher implements teacher{ 2 private student student; 3 4 //主调者的构造方法 5 public mathteacher(student student){ 6 this.student=student; 7 } 8 9 @override 10 public void say() { 11 system.out.println(student.getname()+",叫家长来一下。"); 12 } 13 }
不使用setter方法注入依赖的对象,而是使用构造函数注入依赖的对象。
2、修改spring容器的配置如下
1 <!-- 初始化badstudent类的实例lisi--> 2 <bean name="lisi" class="beans.badstudent"> 3 <constructor-arg value="李四" /> 4 </bean> 5 6 <!--配置依赖--> 7 <bean name="mathteacher" class="beans.mathteacher"> 8 <constructor-arg name="student" ref="lisi" /> 9 </bean>
3、运行,看到控制台打印出“李四,叫家长来一下。”。
说明
- 这两种方式都可以注入java的自带的数据类型。
-
value是注入java的基础类型,ref是注入依赖的bean。当然也可以用<value>、<ref>子元素的形式配置。
推荐阅读
-
Spring学习之依赖注入的方法(三种)
-
浅析依赖注入框架Autofac的使用
-
动手造*:实现一个简单的依赖注入(二) --- 服务注册优化
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
Spring的事务机制实例代码
-
spring boot 注入 property的三种方式(推荐)
-
关于Spring MVC在Controller层中注入request的坑详解
-
PHP中的服务容器与依赖注入的思想
-
C#控制台程序中使用官方依赖注入的实现