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则促进了依赖注入的使用. 如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或 ...
随机推荐
- 自学Python4.2-装饰器
自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...
- PHP-FPM监控shell
!/bin/bash #监控的网页地址url="http://dev2.jwsmed.com" #fastcgi启动/重启/停止脚本路径PROG=/data/fistsoft/ph ...
- [NOI2010]超级钢琴(RMQ+堆)
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中Ai可正可负 ...
- NOIP 飞扬的小鸟 题解
题目描述 Flappy Bird是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣 ...
- 数据库设计E-R图
项目数据库的设计主要划分为以下6个阶段,本篇主要着重来介绍概念设计阶段 A.系统需求分析阶段B.概念结构设计阶段C.逻辑结构设计阶段D.物理结构设计阶段E.数据库实施阶段F.数据库运行与维护阶段 E- ...
- 洛谷P2468 SDOI 2010 粟粟的书架
题意:给你一个矩形书架,每个点是这本书的页数,每次询问(x1,y1)(x2,y2)这个小矩形里最少需要取几本书使得页数和等于Hi. 题解:小数据二位前缀和预处理+二分答案,大数据一行所以用主席树做,感 ...
- 用Python3、NetCore、Shell分别开发一个Ubuntu版的定时提醒(附NetCore跨平台两种发布方式)
汇总系列:https://www.cnblogs.com/dunitian/p/4822808.html#ai Python3 与 C# 基础语法对比:https://www.cnblogs.com/ ...
- socket,tcp,http三者之间的区别和原理
http.TCP/IP协议与socket之间的区别下面的图表试图显示不同的TCP/IP和其他的协议在最初OSI模型中的位置: 7 应用层 例如HTTP.SMTP.SNMP.FTP.Telnet.SIP ...
- 洛谷P1880 石子合并
经典水题....... 断环为链长度乘二,求前缀和区间DP. #include <cstdio> #include <cstring> #include <algorit ...
- A1130. Infix Expression
Given a syntax tree (binary), you are supposed to output the corresponding infix expression, with pa ...