spring源码分析-XXXaware钩子函数

269 阅读3分钟

用途

  • 初始化资源

执行时间见源码

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
         bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
         bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
         bean instanceof ApplicationStartupAware)) {
      return bean;
   }
    //执行各种aware
   invokeAwareInterfaces(bean);
   return bean;
}

private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof EnvironmentAware) {
      ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
   }
   if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
   }
   if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
   }
   if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
   }
   if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
   }
   if (bean instanceof ApplicationStartupAware) {
      ((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
   }
   if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}

各种aware 对比

XXXAware作用触发时间
ApplicationContextAware从ApplicationContextAware获取ApplicationContext上下文的情况,仅仅适用于当前运行的代码和已启动的Spring代码处于同一个Spring上下文,否则获取到的ApplicationContext是空的。初始化前
ApplicationEventPublisherAwareApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口初始化前
ApplicationStartupAware
EmbeddedValueResolverAware获取properties 值始化前
EnvironmentAware凡注册到Spring容器内的bean,实现了EnvironmentAware接口重写setEnvironment方法后,在工程启动时可以获得application.[properties]的配置文件配置的属性值。始化前
MessageSourceAware国际化始化前
BeanNameAware获得到容器中Bean的名称始化前
BeanFactoryAware获得当前bean Factory,从而调用容器的服务始化前
ResourceLoaderAware获取资源加载器,可以获得外部资源文件始化前
  • ApplicationContextAware

  • 从ApplicationContextAware获取ApplicationContext上下文
@Component
public class AppUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        applicationContext = arg0;
    }

    public static Object getObject(String id) {
        Object object = null;
        object = applicationContext.getBean(id);
        return object;
    }
}
  • ApplicationEventPublisherAware

  • ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口
/**
 * @Classname TestApplicationEventPublisherAware
 * @Description TODO
 * @Date 2022-1-28 17:00
 * @Created by zhangxiao
 */
public class TestApplicationEventPublisherAware implements ApplicationEventPublisherAware {
    
    private ApplicationEventPublisher applicationEventPublisher;
    
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        
    }
}
  • EmbeddedValueResolverAware

  • Spring 获取 properties 文件单个属性值,一般使用 @Value 件属性值。下面提供另一种基于Spring解析获取 properties 文件单个属性值的方式,使用 EmbeddedValueResolverAware 。
@Component
// @PropertySource("classpath:/dbconfig.properties")  		//指定 properties 文件,不是必须的
public class PropertiesUtil implements EmbeddedValueResolverAware {

    private StringValueResolver resolver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
    }

    /**
     * 获取属性,直接传入属性名称即可
     * @param key
     * @return
     */
    public String getPropertiesValue(String key) {
        StringBuilder name = new StringBuilder("${").append(key).append("}");
        return resolver.resolveStringValue(name);
    }
}
  • EnvironmentAware

  • 凡注册到Spring容器内的bean,实现了EnvironmentAware接口重写setEnvironment方法后,在工程启动时可以获得application.[properties]的配置文件配置的属性值。
  @Configuration 
  public class MyBatisConfig implements EnvironmentAware {
      private Environment environment;
     @Override
     public void setEnvironment(final Environment environment) {
        this.environment = environment;
    }
    /**
     * 创建数据源(数据源的名称:方法名可以取为XXXDataSource(),XXX为数据库名       称,该名称也就是数据源的名称)
     */
    @Bean
    public DataSource druidDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty("datasource.driverClassName"));
        props.put("url", environment.getProperty("datasource.url"));
        props.put("username", environment.getProperty("datasource.username"));
        props.put("password", environment.getProperty("datasource.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }
    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        // 指定数据源(这个必须有,否则报错)
        fb.setDataSource(druidDataSource());
        fb.setTypeAliasesPackage("com.tf56.pushService.dal.domain");
         // 指定mapper文件          fb.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        return fb.getObject();
    }

}

ResourceLoaderAware

  • spring ResourceLoader为我们提供了一个统一的getResource()方法来通过资源路径检索外部资源。从而将资源或文件(例如文本文件、XML文件、属性文件或图像文件)加载到Spring应用程序上下文中的不同实现
@Component
public class CustomResourceLoader implements ResourceLoaderAware {
    @Autowired
    private ResourceLoader resourceLoader;

    public void showResourceData() throws IOException
    {
        //This line will be changed for all versions of other examples
        Resource banner = resourceLoader.getResource("file:E:\\refreshlog\\log1.txt");

        InputStream in = banner.getInputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        while (true) {
            String line = reader.readLine();
            if (line == null) {
                break;
            }
            System.out.println(line);
        }
        reader.close();
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        try {
            showResourceData();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}