==============================
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 的依赖注入(一)的更多相关文章

  1. SpringBoot系列: 理解 Spring 的依赖注入(二)

    ==============================Spring 容器中 Bean 的名称==============================声明 bean 有两个方式, 一个是 @B ...

  2. Java 系列之spring学习--依赖注入(二)

    一.依赖注入的三种方式 接口注入,set注入,构造函数注入 二.构造函数注入 2.1.测试类 package test; public class test01 { public String msg ...

  3. Spring学习-理解IOC和依赖注入

    最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...

  4. (spring-第3回【IoC基础篇】)spring的依赖注入-属性、构造函数、工厂方法等的注入(基于XML)

    Spring要把xml配置中bean的属性实例化为具体的bean,"依赖注入"是关卡.所谓的"依赖注入",就是把应用程序对bean的属性依赖都注入到spring ...

  5. Spring的依赖注入(DI)三种方式

    Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...

  6. spring的依赖注入是什么意思

    最近学习spring框架,对依赖注入有些模糊,遂上网翻阅资料,做了下列总结,原博客为CSDN 南夏的 spring的依赖注入是什么意思,侵删! Spring 能有效地组织J2EE应用各层的对象.不管是 ...

  7. Spring.NET依赖注入框架学习--简介

    Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入. ...

  8. Spring.NET依赖注入框架学习--入门

    Spring.NET依赖注入框架学习--入门 在学些Spring.net框架之前,有必要先脑补一点知识,比如什么是依赖注入?IOC又是什么?控制反转又是什么意思?它们与Spring.net又有什么关系 ...

  9. Spring和依赖注入的价值

    javaeye上看到有帖子,置疑spring和依赖注入的价值,回复内容整理如下: 依赖注入对设计有利,而spring则促进了依赖注入的使用. 如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或 ...

随机推荐

  1. Hdoj 2563.统计问题 题解

    Problem Description 在一无限大的二维平面中,我们做如下假设: 1. 每次只能移动一格: 2. 不能向后走(假设你的目的地是"向上",那么你可以向左走,可以向右走 ...

  2. 【JDK源码】将JDK源码导入IDEA中

    新建工程 在IDEA中新建普通JAVA工程,步骤如下: 导入源码 首先可以通过如下方法找到工程目录. 在JDK安装目录下找到源码包src.zip,如下图 将src.zip包解压,并将src目录下的内容 ...

  3. urllib的实现---cookie处理

    Cookie的使用 用 Python 来登录网站, 用Cookies记录登录信息, 然后就可以抓取登录之后才能看到的信息. 什么是cookies? Cookie,指某些网站为了辨别用户身份.进行ses ...

  4. iis默认文档

    环境 W10 IIS10 输入网址后,显示一个默认首页,在IIS中,一般指定一个根目录下的文件例如index.html 如果要指定子目录下的文件, 例如让 /home/index.html 这个文件成 ...

  5. HDU 6336 Matrix from Arrays (杭电多校4E)

    遇事不决先打表. 然后会发现(个屁)大的矩形是由一个2L*2L的矩形重复出现组成的然后我们就可以这个矩形分成四个点到(0, 0)点的矩形,这样问题就变成了求四个到顶点(0, 0)的矩形的面积,然后就先 ...

  6. Vue--的src文件

    1.assest: 图片等等...... 2.components: 组件 3.App.vue: 根组件,三个部分:模板.行为(处理逻辑).样式: 模板: 只能有一个根标签: <HelloWor ...

  7. poj1442 Black Box

    The Black Case 好啊! 首先,读题很艰难... 读完题,发现是求第k小的数,那么我们用splay水过对顶堆水过即可. #include <cstdio> #include & ...

  8. Day037--Python--线程的其他方法,GIL, 线程事件,队列,线程池,协程

    1. 线程的一些其他方法 threading.current_thread()  # 线程对象 threading.current_thread().getName()  # 线程名称 threadi ...

  9. 转:mysql分页原理和高效率的mysql分页查询语句

    (转自:http://www.jb51.net/article/46015.htm) 以前我在mysql中分页都是用的 limit 100000,20这样的方式,我相信你也是吧,但是要提高效率,让分页 ...

  10. diff和patch

    diff -u:the unified format会将不同的地方放在一起,紧凑易读 . diff original.txt updated.txt c表示在original文件中的m,n行的内容将要 ...