前言
深入理解Spring源码分为7小节,本小节为Spring源码第三小节,各个小节目录如下。
- 扫描过程
- bean创建过程
3. 容器扩展
- AOP源码分析
- 事务源码分析
- Spring JDBC源码分析
- Spring常用设计模式
Spring提供了众多对外接口,这些接口有一个统一的父接口叫Aware,共有十多个,通过这些接口,我们可以修改Spring容器中大部分东西。
ApplicationContextAware
此接口用于Spring告诉bean应用程序上下文对象,调用时机在对象创建后,我们在上节说过,对象创建成功后,会调用所有BeanPostProcessor尝试修改此对象,具体的实现类是ApplicationContextAwareProcessor。
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);
}
}
在invokeAwareInterfaces()方法下一目了然。
通过EnvironmentAware可以获取所有属性文件中的值。
通过EmbeddedValueResolverAware也可以获取到属性文件中的值,但是获取的方式是这样的。
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.out.println(resolver.resolveStringValue("${name}"));
}
由于应用程序上下文对象都是实现了ResourceLoaderAware的,所以这里传的还是applicationContext,其余也是一样,只不过各个用处不一样。
BeanClassLoaderAware
设置bean的类加载器,调用时期同样在对象创建后初始化对象阶段,这个阶段会调用三个接口,他比上面调用的时机要早。
private void invokeAwareMethods(String beanName, 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用来设置bean的名称,BeanFactoryAware用来设置bean工厂,他的功能比较多,比较实用。
实战
下面假如有以下接口,我们不添加任何实现。
public interface UserMapping {
int count(String id);
}
我们想直接这样使用。
@Component
public class UserTest {
@Autowired
UserMapping userMapping;
}
那要怎么做呢?
为这个接口创建一个代理,添加到容器即可,但问题是,Spring不支持直接添加实例对象到容器,只可以添加BeanDefinition,而BeanDefinition又只能设置class名称,未来会进行实例化,这就僵持住了。
打破的关键是FactoryBean。
首先实现一个ImportBeanDefinitionRegistrar,用来向容器中注册BeanDefinition,而注册的都是FactoryBean对象,Spring会在内部调用他的getObject()方法,并把他放入容器。
public class DatabaseImport implements ImportBeanDefinitionRegistrar {
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<String, Object> mappingScan = importingClassMetadata.getAnnotationAttributes(MappingScan.class.getName());
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
String basePackage = ClassUtils.convertClassNameToResourcePath(((String) mappingScan.get("value")));
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + basePackage + '/' + DEFAULT_RESOURCE_PATTERN;
try {
Resource[] resources = pathMatchingResourcePatternResolver.getResources(packageSearchPath);
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
for (Resource resource : resources) {
MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource);
ClassMetadata classMetadata = metadataReader.getClassMetadata();
boolean anInterface = classMetadata.isInterface()
&& !classMetadata.isAnnotation();
if (anInterface) {
String className = metadataReader.getClassMetadata().getClassName();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MappingFactoryBean.class)
.addConstructorArgValue(className)
.getBeanDefinition();
String beanName = className.substring(className.lastIndexOf(".") + 1);
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这样我们在FactoryBean对象返回代理类即可。
public class MappingFactoryBean<T> implements FactoryBean<T> {
private Class<T> classType;
public MappingFactoryBean(String className) {
try {
this.classType = (Class<T>) Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public T getObject() {
Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{classType}, new MappingInvocationHandler());
return (T) o;
}
@Override
public Class<T> getObjectType() {
return classType;
}
}
定义一个注解,用于Import和指定包路径。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(DatabaseImport.class)
public @interface MappingScan {
String value() default "";
}
@MappingScan("org.springframework.test.dao")
@Component
public class UserTest {
@Autowired
UserMapping userMapping;
}
测试
@MappingScan("org.springframework.test.dao")
@Component
public class UserTest implements InitializingBean {
@Autowired
UserMapping userMapping;
@Override
public void afterPropertiesSet() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println(userMapping.count("a"));
}
}
}
还可以使用InstantiationAwareBeanPostProcessor。
@Component
public class MappingCreateInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("UserMapping".equals(beanName)) {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{beanClass}, new MappingInvocationHandler());
}
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
}