SpringBoot系列: 理解 Spring 的依赖注入(一)
==============================
Spring 的依赖注入
==============================
对于 Spring 程序, Spring 框架为我们提供一个 IoC 容器, 该容器负责创建对象和维护对象之间的依赖关系.
对于普通程序, 我们是通过对象本身来创建和解决自己的依赖问题.
ApplicationContext 即是 Spring 程序的 IoC 容器, 该容器负责创建 Bean, 并将功能类 Bean 注入到你需要的 Bean 中. 那么, Spring 是如何知道我们有哪些 Bean 类, 以及这些类的依赖关系是什么? 有三种配置方式告知 Spring 程序, 分别是 Xml 配置方式/注解配置方式/Java 配置方式.
ApplicationContext 是 Spring 程序的核心, 不管是 Spring 程序, 还是 Spring MVC 程序, 还是SpringBoot 程序, 其 main() 函数最主要的代码就是初始化了 ApplicationContext 容器, Spring 框架为我们提供了多种容器实现, 可以针对不同的应用场景选择.
1. AnnotationConfigApplicationContext: 该容器读取从一个或多个基于 java 的配置类, 适用于 Java 配置方式;
2. AnnotationConfigWebApplicationContext: 专门为 web 应用准备的, 适用于注解方式;
3. XmlWebApplicationContext: 该容器读取一个或多个 Xml 配置文件,使用于 Xml 配置方式;
4. ClassPathXmlApplicationContext, 该容器从 classpath 路径下读取 Xml 配置文件,使用于 Xml 配置方式.
//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");
//ApplicationContext context = new AnnotationConfigApplicationContext(ManConfig.class);
==============================
三种 Bean 配置方式
==============================
1. Xml 配置方式: 老的程序中经常见到, 比如将 Spring bean 声明放到 applicationContext.xml 中.
2. 注解配置方式: 在类定义时通过@Service, @Controller, @Repository, @Component 声明为 Spring Bean.
@Service, 用于业务服务层
@Controller, 用于展现层
@Repository, 用于 DAO 层
@Component, 通用组件, 它是上面 3 个注解的父注解, 没有明确的角色, 对于普通的组件最好使用@Component 注解
3. Java 配置方式: 该方式是通过@Configuration+@Bean 实现的
具体为, 该方式引入了一个 Config 类, 在类中通过方法函数声明 bean 对象, 而 Pojo 类定义不加@Component 之类的注解, Config 类需要加上@Configuration 注解, Config 类中的 bean 方法需要加上@Bean 注解.
@Configuration 等同于 xml 配置中的 <beans> </beans> 标签, 需说明的是@Component 其实也是@Component 的一个子注解,
@Bean 等同于 xml 配置中的 <bean> </bean>标签. @Bean 用来注解一个函数, 该函数应该一个 Bean 对象, Bean 对象的名称是方法名.
最佳实践: 注解配置方式和 Java 配置方式没有孰优孰劣, 理论上是可以相互替换的, 但可以总结一个最佳实践, 全局性的配置使用 Java 配置 (比如数据库相关配置, MVC 相关配置), 业务 Bean 配置使用注解配置, 尽量少用 Xml 配置方式.
==============================
示例程序的 pom.xml
==============================
开发基于 Spring 的命令行程序, 只需要引入 spring-context 即可.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
===============================
基于注解配置示例
===============================
基于注解的配置, 主要在各个 Pojo Class 定义时使用@Component 来声明该类是一个 Spring 的 Bean, 比如 Car/Boss 类都使用的@Component 注解, 依赖注入可以使用@Autowired 或@Resource 注解, 比如在 Boss 类中, 使用了@Autowired 自动注入了一个 Car 对象.
//Car.java
//将 Car 加上注解 @Component, 表明它是一个 Spring bean
@Component
public class Car {
@Override
public String toString() {
return "Brand: Benz, price:1000";
}
}
//Boss.java
//将 Boss 加上注解 @Component, 表明它是一个 Spring bean
//Boss 类的 field Car 是通过 @Autowired 注入的.
@Component
public class Boss {
@Autowired
private Car car; @Override
public String toString() {
return "Boss has one car:("+car+")";
}
}
//SomeConfig.java
//这里创建 SomeConfig 类目的只有一个, 不用准备 Xml 配置文件.
//在 main() 函数中将使用这个 config 类初始化容器, 并加上@ComponentScan, 告知 IoC 容器需要扫描指定 package 来获取 bean 的定义 (包括各种注解了@Component/@Service/@Controller/@Repository 的类).
@Configuration
@ComponentScan("javaTestMaven.demo2")
public class SomeConfig {
}
//App.java
//入口函数,先初始化容器,然后通过容器获得 boss 对象
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig.class);
context.refresh();
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
context.close();
}
}
===============================
基于 Java 配置示例
===============================
基于注解的配置, 主要在各个 Pojo Class 定义时使用@Component 来声明该类是一个 Spring 的 Bean; 但如果使用基于 Java 的配置, Pojo Class 上不需要加上任何 IoC 相关的注解, 而是需要在 Config 类中使用 @Bean 来注解那些需要 Spring 容器管理的对象, @Bean 注解往往加在一个函数体上, 该函数需要返回一个对象.
//Car.java
//Car 类就是一个普通的 Class, 没有加@Component 注解
public class Car {
@Override
public String toString() {
return "Brand: Benz, price:1000";
}
}
//Boss.java
//Boss 类就是一个普通的 Class, 没有加@Component 注解
//Boss 类的 field Car 是通过 @Autowired 注入的.
@Component
public class Boss {
@Autowired
private Car car; @Override
public String toString() {
return "Boss has one car:("+car+")";
}
}
//SomeConfig.java
//在上个示例中 SomeConfig 类目的只有一个, 不用准备 Xml 配置文件.
//这个示例中 SomeConfig 类是一个重点, 不仅加了@Configuration, 而且使用了@Bean 注解定义了多个 Bean 对象
//因为所有的 Bean 都在 SomeConfig 类定义了, 所以 ComponentScan 注解可有可无.
@Configuration
@ComponentScan("javaTestMaven.demo3") //可有可无
public class SomeConfig {
@Bean
public Car car() {
return new Car();
} @Bean
public Boss boss() {
return new Boss();
}
}
//App.java
//入口函数,先初始化容器,然后通过容器获得 boss 对象
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig.class);
context.refresh();
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
context.close();
}
}
===============================
多个 Java 配置类的处理方式
===============================
有时候我们会在多个 Config 类中定义不同的 Bean, 如何告诉 Spring IoC 加在这些 Config 类呢? 有两个方法分别是: 1. 将 Config 类分为主从 Config 两个类别, 在主要 Config 导入从属 Config, 在初始化 Spring 容器的时候只要注册主要 Config 类即可. 2. 不区分中从 Config 类, 在初始化 Spring 容器的时候将这些 Config 类都注册进去.
推荐使用主从 Config 处理方式, 下面是两种处理方式的示例代码, 这个代码是修改自"基于 Java 配置示例", 主要改动是将原来 SomeConfig 分为两个类.
-------------------------------
区分主从 Config 的处理方式
-------------------------------
//SomeConfig1.java
//SomeConfig1 是主 Config, 使用@Import 导入从属的 Config
@Configuration
@Import(SomeConfig2.class)
public class SomeConfig1 {
@Bean
Boss boss() {
return new Boss();
}
}
//SomeConfig2.java
@Configuration
public class SomeConfig2 {
@Bean
public Car car() {
return new Car();
}
}
//App.java
//仅仅导入了主 Config 类
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig1.class);
context.refresh();
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
context.close();
}
}
-------------------------------
不区分主从 Config 的处理方式
-------------------------------
@Configuration
public class SomeConfig1 {
@Bean
Boss boss() {
return new Boss();
}
}
@Configuration
public class SomeConfig2 {
@Bean
public Car car() {
return new Car();
}
}
//App.java
//导入了两个 Config 类
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig1.class);
context.register(SomeConfig2.class);
context.refresh();
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
context.close();
}
}
===============================
Java 配置和注解配置类组合使用
===============================
最佳实践: 注解配置方式和 Java 配置方式没有孰优孰劣, 理论上是可以相互替换的, 但可以总结一个最佳实践, 全局性的配置使用 Java 配置 (比如数据库相关配置, MVC 相关配置), 业务 Bean 配置使用注解配置, 尽量少用 Xml 配置方式.
这本示例中, Boss bean 采用了 Java 配置方式, 而 Car bean 采用注解配置方式.
//Boss.java
//该 Java 没有加任何 IoC 注解
public class Boss {
@Autowired
private Car car; @Override
public String toString() {
return "Boss has one car:("+car+")";
}
}
//Car.java
//该 Java 加上了基于注解的配置说明
@Component
public class Car {
@Override
public String toString() {
return "Brand: Benz, price:1000";
}
}
//SomeConfig.java
//该配置类中仅定义了 boss Bean, 没有直接定义 car Bean, 但实际上 Boss 对象中仍能被成功地注入 Car.
//原因是我们组合使用了基于注解的配置方法, Config 类加上了@ComponentScan 后, IoC 容器能扫描到 Car 类 (因为其被注解为 Component).
@Configuration
@ComponentScan("javaTestMaven.demo3")
public class SomeConfig {
@Bean
Boss boss() {
return new Boss();
}
}
//App.java
//将 Config 类注册一下
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig.class);
context.refresh();
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
context.close();
}
}
===============================
SpringBoot 程序的 @EnableAutoConfiguration
===============================
前面的示例都是基于经典的 Spring 框架, 在程序启动时需要我们将 Config 类主动注册容器上. 而对于 SpringBoot 程序, 因为已经加了 @EnableAutoConfiguration, 所以可以省去注册 Config 类的过程.
下面示例和上一个示例代码只有两处不同, 即 pom.xml 和 App.java 程序.
pom.xml, 引入 spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
//App.java
//基于 SpringBoot 的命令行程序
//无需注册 Config 类
@SpringBootApplication //same as @Configuration @EnableAutoConfiguration @ComponentScan
public class App implements CommandLineRunner {
@Autowired
private ApplicationContext context; public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(App.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
} // Put your logic here.
@Override
public void run(String... args) throws Exception {
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
}
}
//Boss.java
//该 Java 没有加任何 IoC 注解
public class Boss {
@Autowired
private Car car; @Override
public String toString() {
return "Boss has one car:("+car+")";
}
}
//Car.java
//该 Java 加上了基于注解的配置说明
@Component
public class Car {
@Override
public String toString() {
return "Brand: Benz, price:1000";
}
}
//SomeConfig.java
//该配置类中仅定义了 boss Bean, 并加上了@ComponentScan 后, IoC 容器能扫描到 Car 类 (因为其被注解为 @Component)
@Configuration
@ComponentScan("javaTestMaven.demo3")
public class SomeConfig {
@Bean
Boss boss() {
return new Boss();
}
}
===============================
挖掘机技术到底哪家强?
===============================
摘自<<用小说的形式讲解Spring(3) —— xml、注解和Java Config到底选哪个>>
http://bridgeforyou.cn/2017/10/03/Spring-Novel-3-Annotaion-Based-Configuration-and-Java-Based-Configuration/
总结的非常好.

===============================
参考
===============================
http://bridgeforyou.cn/2017/10/03/Spring-Novel-3-Annotaion-Based-Configuration-and-Java-Based-Configuration/
https://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/
https://www.ibm.com/developerworks/cn/java/j-lo-spring25-mvc/
https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-iocannt/index.html
SpringBoot系列: 理解 Spring 的依赖注入(一)的更多相关文章
- SpringBoot系列: 理解 Spring 的依赖注入(二)
==============================Spring 容器中 Bean 的名称==============================声明 bean 有两个方式, 一个是 @B ...
- Java 系列之spring学习--依赖注入(二)
一.依赖注入的三种方式 接口注入,set注入,构造函数注入 二.构造函数注入 2.1.测试类 package test; public class test01 { public String msg ...
- Spring学习-理解IOC和依赖注入
最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...
- (spring-第3回【IoC基础篇】)spring的依赖注入-属性、构造函数、工厂方法等的注入(基于XML)
Spring要把xml配置中bean的属性实例化为具体的bean,"依赖注入"是关卡.所谓的"依赖注入",就是把应用程序对bean的属性依赖都注入到spring ...
- Spring的依赖注入(DI)三种方式
Spring依赖注入(DI)的三种方式,分别为: 1. 接口注入 2. Setter方法注入 3. 构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...
- spring的依赖注入是什么意思
最近学习spring框架,对依赖注入有些模糊,遂上网翻阅资料,做了下列总结,原博客为CSDN 南夏的 spring的依赖注入是什么意思,侵删! Spring 能有效地组织J2EE应用各层的对象.不管是 ...
- Spring.NET依赖注入框架学习--简介
Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入. ...
- Spring.NET依赖注入框架学习--入门
Spring.NET依赖注入框架学习--入门 在学些Spring.net框架之前,有必要先脑补一点知识,比如什么是依赖注入?IOC又是什么?控制反转又是什么意思?它们与Spring.net又有什么关系 ...
- Spring和依赖注入的价值
javaeye上看到有帖子,置疑spring和依赖注入的价值,回复内容整理如下: 依赖注入对设计有利,而spring则促进了依赖注入的使用. 如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或 ...
随机推荐
- 每天一个Linux命令(03):du命令
du命令 今天找开发定位问题,看到他使用了这个命令,查看文件,之前知道df,所以今天的每天系列把这命令 du命令也是查看使用空间的,但是与df命令不同的是Linux du命令是对文件和目录磁盘使用的空 ...
- [NOI2010]航空管制(拓扑排序+贪心)
题目描述 世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生.最近,小X就因为航空管制,连续两次在机场被延误超过了两小时.对此,小X表示很不满意. 在这次来烟台的路上,小X不幸又一 ...
- Oracle数据库中遇到的坑
最近在帮别人忙写程序,用的是Oracle数据库,写一篇文章来说说在Oracle中遇到的一些坑: 1. PL/SQL develop的坑: 由于在这里工作环境是内网完全,无奈只能使用PL/SQL 工具, ...
- Python中何时使用断言 assert
使用断言的最佳时机偶尔会被提起,通常是因为有人误用,因此我觉得有必要写一篇文章来阐述一下什么时候应该用断言,为什么应该用,什么时候不该用. 对那些没有意识到用断言的最佳时机的人来说,Python的断言 ...
- configure: error: no acceptable C compiler found in $PATH 问题解决
解决办法: 安装GCC软件套件 [root@localhost ~]# yum install gccLoaded plugins: fastestmirrorLoading mirror speed ...
- Max Mex
Max Mex 无法直接处理 可以二分答案! [0,mid]是否在同一个链上? 可以不修改地做了 修改? 能不能信息合并?可以! 记录包含[l,r]的最短链的两端 可以[0,k][k+1,mid]合并 ...
- A1132. Cut Integer
Cutting an integer means to cut a K digits lone integer Z into two integers of (K/2) digits long int ...
- 终于解决了用JAVA写窗口程序在不同的windows界面下的显示保持一致。
好像是两三年前的时候发现这个问题. 由于在windows经典界面与windows xp界面下,窗口的标题栏的高度是不一样的. 所以我们在用Java写GUI程序的时候,会遇到一个问题. 当我把一个JFr ...
- 安卓和java开发环境的安装
java配置安卓需要,sdk,jdk(java),adt,eclipse 对于jdk的配置和安装: 1 卸载原来的jdk,重新配置环境变量只需要:在系统变量中把新的jdkJ安装路径写到“JAVA_HO ...
- jenkins学习:jenkins的基本配置
_(:з)∠)_,发现写了gitlab和maven ,但是jenkins的详细步骤没有. 这里整理一下. 1.下载jenkins的war包,无需FQ. 网址:https://jenkins.io/do ...