# Aware 接口

# Aware 接口作用

  • Aware 接口用于注入一些与容器相关信息

    1. BeannameAware 注入 bean 的名字
    2. BeanFactoryAware 注入 BeanFactory 容器
    3. ApplicationContextAware 注入 ApplicationContext 容器
    4. EmbeddedValueResolverAware 处理 ${}
  • 为什么有了 @Autowired 等注解还需要 Aware 接口呢

    1. @Autowired 的解析需要用到 Bean 后处理器,属于扩展功能
    2. 而 Aware 接口属于内置功能,不加任何扩展,Spring 就能识别
    3. 内置的注入和初始化不受扩展功能的影响,总会被执行,因此 Spring 框架内部的类常用它们

# Spring 项目中 @Value 注解失效情况判断

之前很多时候都有这个疑惑,在 JavaConfig 配置 MyBatis 和 DataSource 时,总会出现 @Value 注入失败,现在知道原因了,是 MapperScannerConfigurer 的问题,它是一个 BeanFactroyPostProcessor, 且通过 @Bean 创建,所以在添加 BeanFactroyPostProcessor 步骤就会创建 JavaConfig 实例对象,为了通过工厂方法创建 MapperScannerConfigurer (即 @Bean 注解的方法), 所以这个时候就不会执行依赖注入,初始化,而是在此之后才会进行,而 JavaConfig 类已经实例化了,不会受到 BeanPostProcessor 影响了,自然也就注入失败了

失败代码 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Configuration
@PropertySource(value = {"classpath:dataSource.properties"})
public class JavaConfig {
@Value("${driverName}")
private String driverName;
@Value("${url}")
private String url;
@Value("${user}")
private String username;
@Value("${password}")
private String password;

@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = null;
try {
resources = resolver.getResources("classpath:/mapper/*.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
sqlSessionFactoryBean.setMapperLocations(resources);
return sqlSessionFactoryBean;
}

//就是这个方法导致的注入失败, 因为这个方法继承于BeanDefinitionRegistryPostProcessor, 是工厂后处理器, 在创建BeanFactoryPostProcessor时会生成JavaConfig实例
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.wong.mapper");
return mapperScannerConfigurer;
}
}

解决方法之一 (手动添加):

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
//手动
context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().add("basePackage", "com.wong.mapper"));
context.registerBean("javaConfig", JavaConfig.class);
context.refresh();
MusicCommentMapper mapper = context.getBean(MusicCommentMapper.class);
for (MusicComment musicComment : mapper.getAllByCommentText()) {
System.out.println(musicComment);
}
}
}

正常情况下的执行步骤 :

1
2
3
4
5
6
7
8
9
sequenceDiagram 

ApplicationContext -> BeanFactoryPostProcessor : 1. 执行BeanFactoryPostProcessor
ApplicationContext -> BeanPostProcessor : 2. 注册BeanPostProcessor
ApplicationContext -> Java配置类 : 3. 创建和初始化
BeanPostProcessor -> Java配置类 : 3.1 依赖注入扩展(如@Value和@Autowired)
BeanPostProcessor -> Java配置类 : 3.2 初始化扩展(如@PostConstruct)
ApplicationContext -> Java配置类 : 2.3 执行Aware及InitializingBean
Java配置类 --> ApplicationContext : 3.4 创建成功

失效情况下的执行步骤 :

1
2
3
4
5
6
7
8
9
10
11
12
sequenceDiagram
participant ApplicationContext as ApplicationContext
participant BeanFactoryPostProcessor as BeanFactoryPostProcessor
participant BeanPostProcessor as BeanPostProcessor
participant Java配置类 as Java配置类


ApplicationContext -> Java配置类 : 3. 创建和初始化
ApplicationContext -> Java配置类 : 3.1 执行Aware和InitializingBean
Java配置类 --> ApplicationContext : 3.2 创建成功
ApplicationContext -> BeanFactoryPostProcessor : 1. 执行BeanFactoryPostProcessor
ApplicationContext -> BeanPostProcessor : 2. 注册BeanPostProcessor