共计 5757 个字符,预计需要花费 15 分钟才能阅读完成。
依赖注入 DI 指的是 Spring IoC 容器对对象的依赖对象的处理过程,对象的依赖对象,说起来比拟拗口,其实指的就是:如果一个对象 A 的某一属性为对象 B,则对象 B 就是对象 A 的依赖对象,对象 A 创立的过程中也要创建对象 B 并注入到对象 A,之后对象 A 能力失常工作。
Spring IoC 可通过如下三种形式注入依赖对象:
- 结构器参数
- 工厂办法参数
- Setter 办法
Spring DI 因而也分为两种:基于结构器的 DI 和基于 Setter 的 DI。
咱们须要用代码来阐明 Spring 两种形式 DI 的区别。
代码筹备
创立一个 Spring 我的项目,Spring 的任何版本都能够,在 pom 中退出依赖即可:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
创立两个根底的接口,以及他们的实现类,不须要蕴含任何业务逻辑,咱们只是为了阐明依赖注入的概念。
public interface IDependencyA {public void test();
}
public interface IDependencyB {public void testB();
}
@Service
public class DependencyA implements IDependencyA {
@Override
public void test(){System.out.println("I am DependencyA test...");
}
}
@Service
public class DependencyB implements IDependencyB{
private IDependencyA dependencyA;
public static void main(String[] args) {System.out.println("I am a new comer...hello world");
}
@Override
public void testB(){System.out.print("This is DependencyB's test and ...");
dependencyA.test();}
public DependencyB(){
//this.dependencyA =springTest;
System.out.println("create DependencyB...");
}
}
其中类 DependencyB 蕴含了一个类型为 IDependencyA 的属性 dependencyA,因而,DependencyB 依赖于对象 dependencyA。
在增加一个配置类,配置类啥也不干,仅指定包扫描门路,包扫描门路就是为了通知 Spring 从什么中央加载 bean:
@Configuration
@ComponentScan(value={"SpringTest"})
public class MyConfiguration {}
还要简略约定一下,目前来看 Spring 我的项目应用注解的状况应该会多于应用 xml 配置的状况,因而咱们的文章次要基于注解而非基于 xml 配置文件。除非某些非凡案例只能应用 xml、无奈应用注解代替的状况下,才给出 xml 文件的配置。
最初削减加一个启动类:
public class App {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
System.out.println("Now start to getbean...");
DependencyB dependencyB = applicationContext.getBean(DependencyB.class);
dependencyB.testB();}
}
上面咱们就用这个简略的例子来阐明 Spring 不同的 DI 形式。
基于结构器的 DI
第一步,咱们啥也不干,间接运行启动类:
create DependencyB...
Now start to getbean...
This is DependencyB's test and ...Exception in thread"main" java.lang.NullPointerException
at SpringTest.DependencyB.testB(DependencyB.java:14)
at SpringTest.App.main(App.java:11)
DependencyB 的依赖对象 dependencyA 没有创立,所以报了空指针异样。
咱们并没有给 Spring IoC 任何 DI 的批示,所以 DI 没有工作,dependencyA 没有注入到 dependencyB 中。
基于结构器的 DI 蕴含两种形式:
- 结构器参数
- 工厂办法参数
先来看第一种,通过构造方法参数注入,批改 DependencyB 的构造方法,减少一个 IDependencyA 的参数:
public DependencyB(IDependencyA dependencyA){
this.dependencyA =dependencyA;
System.out.println("create DependencyB...");
}
再次运行启动类:
create DependencyB...
Now start to getbean...
This is DependencyB's test and ...I am DependencyA test...
发现 dependencyA 曾经通过结构器参数胜利注入到 dependencyB 中。
另外一种基于结构器参数的 DI 是通过工厂办法,这种状况下应用 xml 配置会更加不便:
<!-- 工厂办法注入 -->
<bean id="dependencyB" class="springTest.DependencyB" factory-method="factoryMethod"></bean>
指定 factory-method,Spring IoC 会调用该办法创立 bean,能够通过结构器参数 constructor-arg 指定依赖对象实现注入。
DependencyB 须要减少动态工厂办法 factoryMethod:
public static DependencyB factoryMethod(IDependencyA dependencyA){DependencyB dependencyB = new DependencyB();
dependencyB.dependencyA =dependencyA;
System.out.println("create DependencyB...");
return dependencyB;
}
基于 Setter 的 DI
Spring IoC 通过调用对象的 setter 办法注入依赖对象的形式。
咱们去掉 DepedencyB 的构造方法的参数,增加 setDepencyB 办法:
@Component
public class DependencyB implements IDependencyB{
private IDependencyA dependencyA;
public static void main(String[] args) {System.out.println("I am a new comer...hello world");
}
@Override
public void testB(){System.out.print("This is DependencyB's test and ...");
dependencyA.test();}
public void setDependencyA(IDependencyA dependencyA){System.out.println("here you call set method...");
this.dependencyA=dependencyA;
}
public DependencyB(){}
}
而后间接运行启动类:
Now start to getbean...
This is DependencyB's test and ...Exception in thread"main" java.lang.NullPointerException
at springTest.DependencyB.testB(DependencyB.java:14)
at springTest.App.main(App.java:11)
显然是不行的,因为咱们并没有指定 DependencyB 的属性 dependencyA 须要注入,此时 Spring IoC 并不知道须要为 DependencyB 注入什么属性,所以咱们须要显示指定一下(前面咱们会晓得 Spring 其实有主动拆卸的概念,不指定也能够)。
一种形式是通过注解指定,setDependencyA 办法增加 @Autowired 注解:
@Autowired
public void setDependencyA(IDependencyA dependencyA){System.out.println("here you call set method...");
this.dependencyA=dependencyA;
}
再次运行启动类,就 OK 了。@Autowired 注解咱们暂不剖析,前面学习主动拆卸的时候会具体说。
另外一种,当然能够通过 xml 指定,所以咱们须要在我的项目的 resource 目录下创立一个 xml 文件 mySpring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dependencyB" class="springTest.DependencyB">
<property name="dependencyA" ref="dependencyA"/>
</bean>
<bean id="dependencyA" class="springTest.DependencyA">
</bean>
</beans>
在 xml 文件中通过 property 标签,以及 ref 指定了类之间的依赖关系。
咱们还须要从新创立一个基于 xml 的启动类:
public class AppByXML {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("mySpring.xml");
System.out.println("Now start to getbean...");
DependencyB dependencyB = applicationContext.getBean(DependencyB.class);
dependencyB.testB();}
}
运行启动类:
here you call set method...
Now start to getbean...
This is DependencyB's test and ...I am DependencyA test...
dependencyA 被胜利注入了 dependencyB 中了,从 log 中能够清晰的看到 Spring 是通过调用 setter 办法实现注入的。
这种状况下,setter 办法必须是 public 的,否则 Spring 执行注入的时候会因为找不到 setter 办法而抛异样。
基于结构器的 or 基于 Setter 的 DI?
既然有基于结构器的和基于 Setter 的 DI,那咱们在我的项目中应该怎么选?
Spring 官网说,Spring Team 个别举荐应用基于结构器的 DI,因为基于结构器的 DI 有个益处是当你创建对象后,依赖对象也一起筹备好了,能够防止后续业务解决的谬误。
然而对于一个绝对简单的类来说,依赖对象一大堆,结构器就会很俊俏,所以,其实我的项目中还是基于 Setter、或者主动拆卸更好用。
另外,基于结构器和基于 Setter 的 DI 是能够联合应用的,对于强制要求的依赖对象能够放在结构器中,能够在编译阶段就发现依赖对象没有筹备好的问题,防止运行期谬误。
另外一种依赖 depend on
除了咱们下面所说的,一个对象作为另外一个对象的属性这种类型的依赖之外,还有另外一种依赖:一个对象的运行是依赖于另外一个对象的然而另外一个对象并不是以后对象的属性。
这种状况能够应用 @DependsOn 注解或 xml 的 depend on 标签:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
配置很麻烦
你不感觉 DI 的配置、尤其是 xml 形式的配置,很麻烦吗?一个一个的类、其中的一个一个依赖都须要通过 xml 进行配置,尤其是当你须要批改一个类、引入新的依赖对象或者去掉一个依赖对象的时候,你不得不同时关上 xml 配置文件做相应的批改。
的确十分麻烦,然而 Spring 为你想到了一个很好的解决方法:主动拆卸。
下一篇文章学习。
上一篇 Spring FrameWork 从入门到 NB – Ioc