文章

03.Spring IoC 注解

03.Spring IoC 注解

Spring IoC 注解

Xml+ 注解

Spring 的 IOC/DI 对应的配置开发就已经讲解完成,但是使用起来相对来说还是比较复杂的,复杂的地方在==配置文件==。

要想真正简化开发,就需要用到 Spring 的注解开发,Spring 对注解支持的版本历程:

  • 2.0 版开始支持注解
  • 2.5 版注解功能趋于完善
  • 3.0 版支持纯注解开发

步骤

  • 配置 pom.xml,导入 spring-context
1
2
3
4
5
6
7
<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
  </dependencies>
  • 配置 Spring 的注解包扫描:
    • 使用注解需要导入 context 约束,增加注解的支持: resources/applicationContext.xml;
    • 配置扫描包下的注解:context:component-scan
      • Component: 组件, Spring 将管理的 bean 视作自己的一个组件
      • Scan: 扫描
      • Base-package 指定 Spring 框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解;包路径越多,扫描的范围越小速度越快;一般扫描到项目的组织名称即 Maven 的 groupId
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 通过注解的方式注入 -->
    <context:component-scan base-package="me.hacket.spring.model"/>
</beans>
  • 在指定包下编写类,增加注解: @Component

==注意:@Component 注解不可以添加在接口上,因为接口是无法创建对象的。==

1
2
3
4
5
6
7
8
package me.hacket.spring.model;
import org.springframework.stereotype.Component;

// 等价于 <bean id="user" class="me.hacket.spring.model.User2"/>
@Component
public class User2 {
    public String name = "哇哈哈";
}
  • 测试类
1
2
3
4
5
6
@Test
public void testUser2() {
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	User2 user = (User2) context.getBean("user2", User2.class);
	System.out.println(user.name);
}

@Component

  • @Component 相当于 <bean>
  • @Component 的 value 相当于 id
  • 注解写在哪个类上,相当于 class,类的全名
  • @Component 注解如果不起名称,会有一个默认值就是 当前类名首字母小写,所以也可以按照名称获取,如

    1
    2
    
    BookService bookService = (BookService)ctx.getBean("bookServiceImpl");  
    System.out.println(bookService);  ```
    
  • 对于@Component 注解,还衍生出了其他三个注解 @Controller@Service@Repository;这三个注解和@Component 注解的作用是一样的,为什么要衍生出这三个呢? 方便我们后期在编写类的时候能很好的区分出这个类是属于 表现层业务层 还是 数据层 的类。
名称@Component/@Controller/@Service/@Repository
类型类注解
位置类定义上方
作用设置该类为 spring 管理的 bean
属性value(默认):定义 bean 的 id
### 属性注入: @Value 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 等价于 <bean id="user" class="me.hacket.spring.model.User2"/>
@Component
public class User2 {

    public String name = "哇哈哈";

    // 相当于  <property name="name" value="hacket"/>
    @Value("hacket")
    public String name2;

    public void setName2(String name2) {
        this.name2 = name2;
    }
}

衍生的注解

@Component 有几个衍生注解,我们在 web 开发中,会按照 mvc 三层架构分层

  • dao:@Repository
  • service:@Service
  • controller:@Controller

这四个注解功能都是一样的,都是代表将某个类注册到 Spring 中,装配 Bean。

自动装配置

参考 Bean 的自动装配

  • @Autowired : 自动装配通过类型 byType。

如果 Autowired 不能唯一自动装配上属性,则需要通过 @Qualifier(value=“xxx”)

  • @Nullable 字段标记了这个注解,说明这个字段可以为 null;
  • @Resource : 自动装配通过 byName/byType。

作用域:@Scope

  • Singleton:默认的,Spring 会采用单例模式创建这个对象。关闭工厂,所有的对象都会销毁。
  • Prototype:原型模式。关闭工厂,所有的对象不会销毁。内部的垃圾回收机制会回收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 等价于 <bean id="user" class="me.hacket.spring.model.User2"/>
@Component
//@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) // 单例模式
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 原型模式
public class User2 {

    public String name = "哇哈哈";

    // 相当于  <property name="name" value="hacket"/>
    @Value("hacket")
    public String name2;

    public void setName2(String name2) {
        this.name2 = name2;
    }
}

XML 与注解

比较:

  • XML 可以适用任何场景,结构清晰,维护方便。
  • 注解,不是自己提供的类使用不了,维护相对复杂。

xml 与注解整合开发 :

  • XML 用来管理 Bean。
  • 注解只负责完成属性注入。
  • 在使用过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持。
1
2
3
 <!-- 指定要扫描的包,这个包下的注解就会生效! -->
 <context:component-scan base-package="me.hacket.spring.model"/>
<context:annotation-config/>

纯注解开发

可以使用注解来配置 bean, 但是依然有用到配置文件,在配置文件中对包进行了扫描,Spring 在 3.0 版已经支持纯注解开发

  • Spring 3.0 开启了纯注解开发模式,使用 Java 类替代配置文件
  • JavaConfig 原来是 Spring 的一个子项目,在 Spring 4 的版本, JavaConfig 已正式成为 Spring 4 的核心功能。
  • Context 是:AnnotationConfigApplicationContext

纯注解开发步骤

  • 将配置文件 applicationContext.xml 删除掉,使用类来替换。
  • 编写一个实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class User3 {
    private String name;

    public String getName() {
        return name;
    }

    @Value("hacket zeng") //属性注入值
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User3{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • 新建一个 config 配置包,编写一个 SunConfig.java 配置类
    • 在配置类上添加 @Configuration 注解,将其标识为一个配置类, 替换 applicationContext.xml
    • 在配置类上添加包扫描注解 @ComponentScan 替换 <context:component-scan base-package=""/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration  // 代表这是一个配置类
@ComponentScan("me.hacket.spring.model")
public class SunConfig {

    // 注册一个bean,就相当于我们之前写的一个bean标签;
    // 这个方法的名字,就相当bean标签中的id属性;
    // 这个方法的返回值,就相当bean标签中的cLass属性;
    @Bean
    public User getUser() {
        return new User(); // 就是返回要注入到bean的对象
    }
}
  • 测试
1
2
3
4
5
6
7
8
9
public class MyTest {
    // 如果完全使用了配置类方式去做,我们就只能通过Annotationconfig 上下文来获收容器,通过配置类的class对象加载!
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(SunConfig.class);
        User user = (User) applicationContext.getBean("getUser");
        System.out.println(user.getName());
    }
}
  • 导入其他配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 其他的配置类
@Configuration //代表这是一个配置类
public class SunConfig2 {
    @Bean
    public User3 getUser3() {
        return new User3(); // 就是返回要注入到bean的对象
    }
}

// 导入
@Configuration  // 代表这是一个配置类
@ComponentScan("me.hacket.spring.model")
@Import(SunConfig2.class) // 导入合并其他配置类,类似于配置文件中的 inculde 标签
public class SunConfig {

    // 注册一个bean,就相当于我们之前写的一个bean标签;
    // 这个方法的名字,就相当bean标签中的id属性;
    // 这个方法的返回值,就相当bean标签中的cLass属性;
    @Bean
    public User getUser() {
        return new User(); // 就是返回要注入到bean的对象
    }
}
  • 这种纯 Java 的配置方式,在 SpringBoot 中随处可见

注解开发 bean 作用范围与生命周期管理

1
2
3
4
5
6
7
8
9
10
@Repository  
//@Scope设置bean的作用范围  
@Scope("prototype")  
public class BookDaoImpl implements BookDao {  
  
    public void save() {  
        System.out.println("book dao save ...");    
        }
	}  
}

@Scope

名称@Scope
类型类注解
位置类定义上方
作用设置该类创建对象的作用范围
可用于设置创建出的 bean 是否为单例对象
属性value(默认):定义 bean 作用范围,
==默认值 singleton(单例),可选值 prototype(非单例)==

Bean 的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    public void init() {
        System.out.println("init ...");
    }
    public void destroy() {
        System.out.println("destroy ...");
    }
}

如何对方法进行标识,哪个是初始化方法,哪个是销毁方法?

如何对方法进行标识,哪个是初始化方法,哪个是销毁方法?

只需要在对应的方法上添加 @PostConstruct@PreDestroy 注解即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    @PostConstruct //在构造方法之后执行,替换 init-method
    public void init() {
        System.out.println("init ...");
    }
    @PreDestroy //在销毁方法之前执行,替换 destroy-method
    public void destroy() {
        System.out.println("destroy ...");
    }
}

要想看到两个方法执行,需要注意的是 destroy 只有在容器关闭的时候,才会执行,所以需要修改 App 的类

1
2
3
4
5
6
7
8
9
10
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao1 = ctx.getBean(BookDao.class);
        BookDao bookDao2 = ctx.getBean(BookDao.class);
        System.out.println(bookDao1);
        System.out.println(bookDao2);
        ctx.close(); //关闭容器
    }
}

==注意:@PostConstruct 和@PreDestroy 注解如果找不到,需要导入下面的 jar 包==

1
2
3
4
5
<dependency>  
  <groupId>javax.annotation</groupId>  
  <artifactId>javax.annotation-api</artifactId>  
  <version>1.3.2</version>
</dependency>  

找不到的原因是,从 JDK 9 以后 jdk 中的 javax. Annotation 包被移除了,这两个注解刚好就在这个包中。

@PostConstruct
名称@PostConstruct
类型方法注解
位置方法上
作用设置该方法为初始化方法
属性
@PreDestroy
名称@PreDestroy
类型方法注解
位置方法上
作用设置该方法为销毁方法
属性

注解开发依赖注入

Spring 为了使用注解简化开发,并没有提供 构造函数注入setter注入 对应的注解,只提供了自动装配的注解实现。

注解实现按照类型注入 @Autowired

单个实现

BookServiceImpl 类的 bookDao 属性上添加 @Autowired 注解

1
2
3
4
5
6
7
8
9
10
11
12
@Service  
public class BookServiceImpl implements BookService {  
    @Autowired  
    private BookDao bookDao;  
    //    public void setBookDao(BookDao bookDao) {  
//        this.bookDao = bookDao;  
//    }  
    public void save() {  
        System.out.println("book service save ...");        
        bookDao.save();  
    }
}  

注意:

  • @Autowired 可以写在属性上,也可也写在 setter 方法上,最简单的处理方式是 写在属性上并将setter方法删除掉
  • 为什么 setter 方法可以删除呢?
    • 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
    • 普通反射只能获取 public 修饰的内容
    • 暴力反射除了获取 public 修饰的内容还可以获取 private 修改的内容
    • 所以此处无需提供 setter 方法
多个实现

@Autowired 是按照类型注入,那么对应 BookDao 接口如果有多个实现类,比如添加 BookDaoImpl2

1
2
3
4
5
6
@Repository
public class BookDaoImpl2 implements BookDao {
    public void save() {
        System.out.println("book dao save ...2");
    }
}

这个时候再次运行 App,就会报错。

此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入

  • 先给两个 Dao 类分别起个名称
1
2
3
4
5
6
7
8
9
10
11
12
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
	public void save() {
		System.out.println("book dao save ..." );
	}
}
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
	public void save() {
		System.out.println("book dao save ...2" );
	}
}

此时就可以注入成功,但是得思考个问题:

  • @Autowired 是按照类型注入的,给 BookDao 的两个实现起了名称,它还是有两个 bean 对象,为什么不报错?
  • @Autowired 默认按照类型自动装配,如果 IOC 容器中同类的 Bean 找到多个,就按照变量名和 Bean 的名称匹配。因为变量名叫 bookDao 而容器中也有一个 booDao,所以可以成功注入。
  • 分析下面这种情况是否能完成注入呢?

不行,因为按照类型会找到多个 bean 对象,此时会按照 bookDao 名称去找,因为 IOC 容器只有名称叫 bookDao1bookDao2, 所以找不到,会报 NoUniqueBeanDefinitionException

注解实现按照名称注入 @Qualifier

当根据类型在容器中找到多个 bean,注入参数的属性名又和容器中 bean 的名称不一致,这个时候该如何解决,就需要使用到 @Qualifier 来指定注入哪个名称的 bean 对象。

1
2
3
4
5
6
7
8
9
10
11
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao1")
    private BookDao bookDao;
    
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

@Qualifier 注解后的值就是需要注入的 bean 的名称。

==注意:@Qualifier 不能独立使用,必须和@Autowired 一起使用==

简单数据类型注入 @Value

引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型。

数据类型换了,对应的注解也要跟着换,这次使用 @Value 注解,将值写入注解的参数中就行了

1
2
3
4
5
6
7
8
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("name_di")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

注意数据格式要匹配,如将 “abc” 注入给 int 值,这样程序就会报错。

介绍完后,会有一种感觉就是这个注解好像没什么用,跟直接赋值是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?

注解读取 properties 配置文件

@Value 一般会被用在从 properties 配置文件中读取内容进行使用,具体如何实现?

步骤 1:resource 下准备 properties 文件

jdbc.properties

1
name=hacket
步骤 2: 使用注解加载 properties 配置文件

在配置类上添加 @PropertySource 注解

1
2
3
4
5
6
@Configuration
@ComponentScan("com.example")
@PropertySource("jdbc.properties")
public class SpringConfig {
}

步骤 3:使用@Value 读取配置文件中的内容
1
2
3
4
5
6
7
8
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

注意:

  • 如果读取的 properties 配置文件有多个,可以使用 @PropertySource 的属性来指定多个

    1
    
    @PropertySource({"jdbc.properties","xxx.properties"})  
    
  • @PropertySource 注解属性中不支持使用通配符 *,运行会报错

    1
    
    @PropertySource({"*.properties"})  
    
  • @PropertySource 注解属性中可以把 classpath: 加上,代表从当前项目的根路径找文件

    1
    
    @PropertySource({"classpath:jdbc.properties"})  
    

IOC/DI 注解开发管理第三方 bean

前面定义 bean 的时候都是在自己开发的类上面写个注解就完成了,但如果是第三方的类,这些类都是在 jar 包中,我们没有办法在类上面添加注解,这个时候该怎么办?

遇到上述问题,我们就需要有一种更加灵活的方式来定义 bean,这种方式不能在原始代码上面书写注解,一样能定义 bean,这就用到了一个全新的注解==@Bean==。

注解开发管理第三方 bean @Bean

  • 导入对应的 jar 包
1
2
3
4
5
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>
  • 在配置类中添加一个方法: 注意该方法的返回值就是要创建的 Bean 对象类型
  • 在方法上添加@Bean 注解;@Bean 注解的作用是将方法的返回值制作为 Spring 管理的一个 bean 对象
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class SpringConfig {
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

注意: 不能使用 DataSource ds = new DruidDataSource(),因为 DataSource 接口中没有对应的 setter 方法来设置属性。

如果有多个 bean 要被 Spring 管理,直接在配置类中多些几个方法,方法上添加@Bean 注解即可。

引入外部配置类

如果把所有的第三方 bean 都配置到 Spring 的配置类 SpringConfig 中,虽然可以,但是不利于代码阅读和分类管理,所有我们就想能不能按照类别将这些 bean 配置到不同的配置类中?

对于数据源的 bean,我们新建一个 JdbcConfig 配置类,并把数据源配置到该类下。

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

现在的问题是,这个配置类如何能被 Spring 配置类加载到,并创建 DataSource 对象在 IOC 容器中?

针对这个问题,有两个解决方案:

使用包扫描引入

  • 在 Spring 的配置类上添加包扫描
1
2
3
4
5
@Configuration
@ComponentScan("com.example.config")
public class SpringConfig {
	
}
  • JdbcConfig 上添加配置注解

JdbcConfig 类要放入到 com.example.config 包下,需要被 Spring 的配置类扫描到即可

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class JdbcConfig {
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

使用@Import 引入

方案一实现起来有点小复杂,Spring 早就想到了这一点,于是又给我们提供了第二种方案。

这种方案可以不用加 @Configuration 注解,但是必须在 Spring 配置类上使用 @Import 注解手动引入需要加载的配置类

  • 去除 JdbcConfig 类上的注解: @Configuration
  • 在 Spring 配置类中引入
1
2
3
4
5
6
@Configuration
//@ComponentScan("com.example.config")
@Import({JdbcConfig.class})
public class SpringConfig {
	
}

注意:

  • 扫描注解 @ComponentScan 可以移除
  • @Import 参数需要的是一个数组,可以引入多个配置类。
  • @Import 注解在配置类中只能写一次,下面的方式是==不允许的==
1
2
3
4
5
6
7
@Configuration
//@ComponentScan("com.example.config")
@Import(JdbcConfig.class)
@Import(Xxx.class)
public class SpringConfig {
	
}

涉及到的注解

@Bean

名称@Bean
类型方法注解
位置方法定义上方
作用设置该方法的返回值作为 spring 管理的 bean
属性value(默认):定义 bean 的 id

@Import

名称@Import
类型类注解
位置类定义上方
作用导入配置类
属性value(默认):定义导入的配置类类名,
当配置类有多个时使用数组格式一次性导入多个配置类

注解开发实现为第三方 bean 注入资源

在使用 @Bean 创建 bean 对象的时候,如果方法在创建的过程中需要其他资源该怎么办?

这些资源会有两大类,分别是 简单数据类型 和 引用数据类型

简单数据类型

现状:对于下面代码关于数据库的四要素不应该写死在代码中,应该是从 properties 配置文件中读取。如何来优化下面的代码?

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

步骤:

  1. resources 目录下添加 jdbc.properties
  2. 配置文件中提供四个键值对分别是数据库的四要素
  3. 使用 @PropertySource 加载 jdbc.properties 配置文件
  4. 修改 @Value 注解属性的值,将其修改为 ${key},key 就是键值对中的键的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class JdbcConfig {
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;
    @Value("root")
    private String userName;
    @Value("password")
    private String password;
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

引用数据类型

假设在构建 DataSource 对象的时候,需要用到 BookDao 对象,该如何把 BookDao 对象注入进方法内让其使用呢?

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
	@Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

==引用类型注入只需要为 bean 定义方法设置形参即可,容器会根据类型自动装配对象。==

1
2
3
4
5
6
7
8
9
10
@Bean
public DataSource dataSource(BookDao bookDao){
    System.out.println(bookDao);
    DruidDataSource ds = new DruidDataSource();
    ds.setDriverClassName(driver);
    ds.setUrl(url);
    ds.setUsername(userName);
    ds.setPassword(password);
    return ds;
}

纯注解开发小结

  • Java 类替换 Spring 核心配置文件
  • @Configuration 注解用于设定当前类为配置类
  • @ComponentScan 注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
1
  @ComponentScan({com.example.service","com.example.dao"})  
  • 读取 Spring 核心配置文件初始化容器对象切换为读取 Java 配置类初始化容器对象

    1
    2
    3
    4
    
    // 加载配置文件初始化容器  
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
    // 加载配置类初始化容器  
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);  
    

涉及到的注解

@Configuration
名称@Configuration
类型类注解
位置类定义上方
作用设置该类为 spring 配置类
属性value(默认):定义 bean 的 id
@ComponentScan
名称@ComponentScan
类型类注解
位置类定义上方
作用设置 spring 配置类扫描路径,用于加载使用注解格式定义的 bean
属性value(默认):扫描路径,此路径可以逐层向下扫描
@Autowired
名称@Autowired
类型属性注解或方法注解(了解) 或方法形参注解(了解)
位置属性定义上方或标准 set 方法上方或类 set 方法上方或方法形参前面
作用为引用类型属性设置值
属性required:true/false,定义该属性是否允许为 null
@Qualifier
名称@Qualifier
类型属性注解或方法注解(了解)
位置属性定义上方或标准 set 方法上方或类 set 方法上方
作用为引用类型属性指定注入的 beanId
属性value(默认):设置注入的 beanId
@Value
名称@Value
类型属性注解或方法注解(了解)
位置属性定义上方或标准 set 方法上方或类 set 方法上方
作用为基本数据类型或字符串类型属性设置值
属性value(默认):要注入的属性值
@PropertySource
名称@PropertySource
类型类注解
位置类定义上方
作用加载 properties 文件中的属性值
属性value(默认):设置加载的 properties 文件对应的文件名或文件名组成的数组

bean.xml 和注解对应关系

XML 配置和注解差异:

本文由作者按照 CC BY 4.0 进行授权