模拟Spring IoC容器 2.0
Spring的IoC容器通过解析xml文件,读取当中的配置关系,从而在对象中注入值或其他对象。反射机制在当中扮演重要角色,为了更简便地操作反射,Java中有一种技术Introspector(网上翻译为内省),模拟中,有了它,配置Bean标签的属性和依赖关系,会简便得多。当然,直接用反射也是可以的。
Introspector
- java.beans.Introspector
源码如是说:Introspector 提供一种标准方法来访问目标Java Bean的属性、事件、方法。对于一个Java Bean的这3种信息,Introspector 会别分析,还会分析父类的这3种信息,不论是显式还是隐式。Introspector会根据这些信息创建一个BeanInfo对象来描述这个Java Bean。就像有个Class类来描述class,当中渗透着面向对象思想。
此2.0模拟,运用面向对象思想,把xml解析出来的对象封装到Bean对象中
The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.
该技术的关键方法有
- getBeanInfo(),获得JavaBean的信息。JDK1.7后,增加能够标识分析到哪个父类为止的方法重载
public static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass, int flags){...}
//Instrospect一个Java Bean,获取其属性、事件、方法。若已经Instropect过,则从缓存中取相关信息
public static BeanInfo getBeanInfo(Class<?> beanClass)
throws IntrospectionException
{
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (declaredMethodCache) {
beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (declaredMethodCache) {
context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
}
- getPropertyDescriptors(),获得属性的描述,可以采用遍历BeanInfo的方法,来查找、设置类的属性。该方法在BeanInfo类下。Spring的org.springframework.beans.ExtendedBeanInfo继承了BeanInfo.源码如下:
public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
this.delegate = delegate;
//获取属性描述器
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
try {
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
new SimplePropertyDescriptor(pd));
}
catch (IntrospectionException ex) {
// 可能没有按照JavaBean规范些方法...
if (logger.isDebugEnabled()) {
logger.debug("Ignoring invalid bean property '" + pd.getName() + "': " + ex.getMessage());
}
}
}
//获取方法描述器
MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors();
if (methodDescriptors != null) {
//获取setter
for (Method method : findCandidateWriteMethods(methodDescriptors)) {
try {
handleCandidateWriteMethod(method);
}
catch (IntrospectionException ex) {
// We're only trying to find candidates, can easily ignore extra ones here...
if (logger.isDebugEnabled()) {
logger.debug("Ignoring candidate write method [" + method + "]: " + ex.getMessage());
}
}
}
}
}
对于内省操作,Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包,地址http://commons.apache.org/proper/commons-beanutils/