还记的我们在#CreateBean(...)方法中其中有一个过程是初始化bean的过程,在初始化的方法中我们其中有一个过程是激活Aware的方法的过程,这节我们来看看Aware到底是什么
Aware接口
该接口位于org.springframework.beans.factory包下
/**
* A marker superinterface indicating that a bean is eligible to be notified by the
* Spring container of a particular framework object through a callback-style method.
* The actual method signature is determined by individual subinterfaces but should
* typically consist of just one void-returning method that accepts a single argument.
*
* <p>Note that merely implementing {@link Aware} provides no default functionality.
* Rather, processing must be done explicitly, for example in a
* {@link org.springframework.beans.factory.config.BeanPostProcessor}.
* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
* for an example of processing specific {@code *Aware} interface callback
*/
public interface Aware {
}
该接口主要的作用是一个标记超级接口,实现了该接口的bean是具有回调spring容器的能力,我们可以看到,是一个空接口,实际方法的签名是由各个子接口来实现,通常只接受返回单个参数的seter方法,我们来看一下我们的激活Aware方法的代码:
AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
代码简单:
- 如果是BeanNameAware类型的话,调用setXX方法设置属性
- 如果是BeanClassLoaderAware类型的话,调用setBeanClassLoader设置属性
- 如果是beanFactoryAware类型的话,调用setBeanFactory设置属性
Aware的实现类
我们来看一下实现了Aware接口的子类
这只是其中的一部分实现,图来自大佬芋艿的博客,大家可以去看看,接下来我们自己可以实现自己的Aware方法:
''''''
public interface BeanClassLoaderAware extends Aware {
/**
* 将 BeanClassLoader 提供给 bean 实例回调
* 在 bean 属性填充之后、初始化回调之前回调,
* 例如InitializingBean的InitializingBean.afterPropertiesSet()方法或自定义init方法
*/
void setBeanClassLoader(ClassLoader classLoader);
public interface BeanFactoryAware extends Aware {
/**
* 将 BeanFactory 提供给 bean 实例回调
* 调用时机和 setBeanClassLoader 一样
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
public interface BeanNameAware extends Aware {
/**
* 在创建此 bean 的 bean工厂中设置 beanName
*/
void setBeanName(String name);
}
public interface ApplicationContextAware extends Aware {
/**
* 设置此 bean 对象的 ApplicationContext,通常,该方法用于初始化对象
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
常见的四种实现Aware接口的子类,我们来看case
public class MyAwareCase implements
BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, ApplicationContextAware {
private String beanName;
private ClassLoader classLoader;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("调用:BeanClassLoaderAware的setBeanClassLoader方法");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("调用:BeanFactoryAware的setBeanFactory方法");
}
public void setBeanName(String name) {
this.beanName = name;
System.out.println("调用:BeanNameAware的setBeanName方法");
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("调用:ApplicationContextAware的setApplicationContext方法");
}
public void display(){
System.out.println("beanName:" + beanName);
System.out.println("是否为单例:" + beanFactory.isSingleton(beanName));
System.out.println("系统环境为:" + applicationContext.getEnvironment());
}
测试方法如下:
public class AwareTest {
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("awareConfig.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
MyAwareCase myAwareCase = (MyAwareCase)factory.getBean("myAwareCase");
myAwareCase.display();
}
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myAwareCase" class="com.sgcc.aware.MyAwareCase">
<property name="beanName" value="beanName"/>
<property name="beanFactory" value="beanFactory"/>
<property name="beanClassLoader" value="beanClassLoader"/>
<property name="applicationContext" value="applicationContext"/>
</bean>
</beans>
很意外,我运行时报了一个错误,大概知道问题所在,这里我把错误贴出来,有知道解决的可以留个言,在这里我先谢过了
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.beans.factory.BeanFactory' for property 'beanFactory'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.beans.factory.BeanFactory' for property 'beanFactory': no matching editors or conversion strategy found
at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:604)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:219)
从异常信息来看是因为属性beanFactory在匹配类型的过程中出现的问题.它需要的是一个BeanFactory类型的属性value,我这里是String,可能是这个原因造成的
总结
经过简单的case,我们发现Aware接口的实质,spring主要来检测当前bean是否实现了Aware接口,如果实现了,则通过setxxx设置对应的属性给bean,之后我们的bean就有了从spring容器中获取资源的权限了......
网友评论