Spring最成功的的是其提出来的理念,而不是技术本身。它所依赖的两个核心概念,一个是控制翻转(Inversion of Control, IoC),另一个是面向切面编程(Aspect Oriented Programming,AOP)
IoC 是一种通过描述来生成或者获取对象(Bean)的技术,这个技术不是 Spring 甚至不是 Java 独有的。平时最熟悉的是使用 new 关键字来创建对象,而在 Spring 中则不是,它是通过描述来创建对象。Spingt Boot 中建议使用注解描述生成对象而不是使用 XML。
Spring 中把每一个需要管理的对象称为 Spring Bean(简称 Bean),管理这些 Bean 的容器称为 Spring IoC 容器(或者简称 IoC 容器)。IoC 容器具备两个基本的功能:通过描述管理 Bean(包括发布和获取 Bean)和通过描述完成 Bean 之间的依赖关系
Spring IoC 容器总,可以按类型(by type)或者按名称(by name)获取 Bean,默认情况下 Bean 都是以单例存在的。
使用@Bean 注解装配 Bean
```java
@Configuration
public class BeanConfig {
@Bean(name = "user")
public User initUser() {
User user = new User();
user.setUsername("Jack");
user.setAge(18); return user;
}
}
@Configuration 表示这是一个 Java 配置文件,Spring 容器会根据它来生成 IoC 容器去装配 Bean @Bean 表示将 initUser 方法返回的 POJO 装配到 IoC 容器中,属性 name 定义 Bean 的名称,如果没有设置该属性,则默认使用方法名称 initUser 作为 Bean 的名称保存到 Spring IoC 容器中
通过扫描装配 Bean
如果使用@Bean 一个个的装配,将是一件很麻烦的事情,Spring 也意识到了这点,允许使用扫描的方式进行装配,使用的注解是@Component 和@ComponentScan,@Component 标明哪个类被扫描进入 Spring IoC 容器,而@ComponentScan 则是标明采用何种策略扫描装配 Bean
```java
package com.test.example.config;
@Component("user")
public class User {
@Value("Jack")
private String username;
@Value("18")
private int age;
}
@Component 标明该类将被 Spring IoC 容器扫描装配,其中配置的 user 则是 Bean 的名称,如果不配置,则 IoC 容器默认会把类名第一个字母作为小写,其他不变作为 Bean 名称 @Value 指定具体的值,使得 Spring IoC 给予对应的属性注入对应的值
为了 Spring IoC 容器装配这个类,调整 BeanConfig
package com.test.example.config;
@Configuration
@ComponentScan
public class BeanConfig {
}
@ComponentScan 标明会进行扫描,默认只是扫描 BeanConfig 所在的当前 package 和子 package,可以观察到 User 也在该 package 下面,但是这样设置太不合理,为了更加合理,运行@ComponentScan 扫描自定义的包
@ComponentScan(basePackages = {
" com.test.example.pojo"})
包名可以采用正则表达式匹配,但是这个也有不合理的地方,比如不想加载某些 Bean,比如定义一个 UserService 类,将它标记为@Service(该注解已经注入了@Component)服务类,则也会被 Spring 扫描装配到 IoC 容器中,如果不希望这些服务类被装配,则可以通过设置 excludeFilters
@ComponentScan(basePackages = {
" com.test.example.*", excludeFilters = {
@Filter(classes = {
Service.class})}})
由于加入 excludeFilters 设置,则使用@Service 注解的服务类不会被扫描注入
实际项目中经常需要引入许多第三方的包,并且希望把第三方包的类对象放入到 Spring IoC 容器中,这时需要使用@Bean 注解
定义一个数据源
@Bean(name = "dataSource")
public DataSource getDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.mysql.jdbc.Driver"); props.setProperty("url", "jdbc:mysql://localhost:3306/test"); props.setProperty("username", "root");
props.setProperty("password", "root");
DataSource dataSource = null; try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
通过@Bean 的 name 配置 Bean 名称为“dataSource”,如果不设置 name 属性,默认会使用方法名称作为 Bean 名称保存到 IoC 容器中。
上半部分主要讨论了 Bean 如何装载到 IoC 容器中,对于如何获取以及 Bean 之间的依赖,在 Spring IoC 概念中称为依赖注入(Dependency Injection,DI)
Spring 中最常用注解之一,可以标注属性、方法、参数。
根据类型(by type)获取 Bean,@Autowired 是一个默认必须找到对应 Bean 的注解,如果不确定其标注的属性一定存在并且允许被标注的属性为 Null,可以设置 required 属性为 false
@Autowired(require = false)
@Primary 是一个修改优先权的注解,其目的当发现有多个同类型的 Bean 时,高速 IoC 容器优先使用该注解标记的 Bean,但是它也可以被标注到多个 Bean 上,这时 IoC 容器还是无法区分要采用哪个 Bean 实例,此时需要使用@Qualifier 的 value 来进行设置
@Qualifier 和@Autowired 组合在一起就是通过类型和名称一起找到 Bean,Bean 的名称在 IoC 容器中是唯一的,如
@Autowired
@Qualifier("dog")
private Animal animal = null;
带有参数的构造方法类装配
public ConstructorAnimal(@Autowired @Qualifier("dog") Animal animal) {
... }