Spring的核心是IOC和AOP
AOP之前介绍了,核心是使用动态代理包装了一层。
IOC使用到的Java技术是用反射去解析注解。
下面这个类是模拟xml的配置文件,省略对xml文件解析的麻烦。其中的注解都可以自己定义,具体可下载代码查看
package annocation.my;
@Configuration
public class BeansXML {
@Bean("bookHotel")
public IBook bookHotel() {
return new BookHotelImpl();
}
@Bean
//注册的Bean名称为方法名
public IBook bookRestaurant() {
return new BookRestaurantImpl();
}
@Bean("holiday")
public Holiday funnyHoliday() {
return new Holiday();
}
}
注解解析程序,注解的获取是从class类得到。处理流程:解析xml(类),用map保存name和类地址的映射。getBean时,对那个类进行解析,类中有Bean注解的方法/属性获取到和Map中的对比。然后注入加载即可。
package annocation.my;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ApplicationContext {
// 配置文件类
private Class<?> configClass;
// 配置文件类中Bean,只处理使用@Bean标注的方法,没有注解的方法将被忽略
// Map<注解名称,注解方法>
private Map<String, Method> mapMethods;
// 构造函数
public ApplicationContext(Class<?> configClass) {
this.configClass = configClass;
// 检查配置文件类
if (checkConfigClass()) {
// 读取配置文件类的方法
mapMethods = getDeclaredMethods(configClass);
}
}
// 判断配置文件类是否使用了@Configuration注解
private boolean checkConfigClass() {
Boolean useConfiguration = false;
try {
useConfiguration = configClass
.isAnnotationPresent(Configuration.class);
if (!useConfiguration) {
System.out.println("[配置文件类:" + configClass.getName()
+ " 缺少@Configuration注解]");
}
} catch (Exception e) {
System.out.println("[读取配置文件类失败]" + e);
}
return useConfiguration;
}
// 获取一个类中所有使用了@Bean注解的方法
private Map<String, Method> getDeclaredMethods(Class<?> clazz) {
Map<String, Method> resultMap = new HashMap<String, Method>();
try {
for (Method m : clazz.getDeclaredMethods()) {
// 获取每个方法的@bean注解
Bean beanMethod = m.getAnnotation(Bean.class);
if (null != beanMethod) {
// @Bean没有自定义value,使用方法名称作为value
String annoName = beanMethod.value();
annoName = ("".equals(annoName)) ? m.getName() : annoName;
resultMap.put(annoName, m);
}
}
} catch (Exception e) {
System.out.println("[读取配置文件类Bean定义出错]" + e);
}
return resultMap;
}
// 获取类实例,只能调用无参的构造函数
private <T> T getInstance(Class<T> clazz) {
T instance = null;
try {
instance = clazz.newInstance();
} catch (Exception e) {
System.out.println("[实例化配置文件类失败,类名称: " + clazz.getName() + "]" + e);
}
return instance;
}
// 字符串的第一个字母转换为大写
private String getMethodName(String fildeName) {
byte[] items = fildeName.getBytes();
items[0] = (byte) ((char) items[0] - 'a' + 'A');
return new String(items);
}
/**
* 根据bean名称获取bean
*
* @param beanName
* 注册的Bean名称
*/
@SuppressWarnings("unchecked")
public <T> T getBean(String beanName) {
// Bean实例
T instance = null;
// 配置文件类的实例
Object configObj = getInstance(configClass);
// 遍历所有定义的Bean
Set<String> annoNames = (Set<String>) mapMethods.keySet();
for (String annoName : annoNames) {
// 对应的方法
Method m = mapMethods.get(annoName);
// 对入参进行匹配
if (beanName.equals(annoName)) {
try {
// 获取实例
instance = (T) m.invoke(configObj);
// 实例对象对应的Class类型
Class<?> instanceClass = instance.getClass();
// 注入依赖(实例化@Resource引用的Bean)
for (Field fs : instanceClass.getDeclaredFields()) {
// 读取属性上的@Resource注解信息
Resource resField = fs.getAnnotation(Resource.class);
if (null != resField) {
// 获取注解值
String ResValue = resField.value();
// 判断是否已在配置文件类中已注册
Method refM = mapMethods.get(ResValue);
if (null != refM) {
try {
// 获取属性对应的标准setter方法名称
String setterName = "set"
+ getMethodName(fs.getName());
// 根据名称和入参类型获取setter方法
Method setter = instanceClass.getMethod(
setterName, fs.getType());
// 执行setter方法注入属性值
// refM.invoke(configObj) 将返回一个配置文件类中的实例
setter.invoke(instance,
refM.invoke(configObj));
} catch (Exception e) {
System.out.println("[类:"
+ instance.getClass().getName()
+ ",属性:" + fs.getName()
+ " 缺少标准的setter()方法]" + e);
}
} else {
System.out.println("[配置文件类中未找到对应的Bean:"
+ ResValue + "]");
}
}
}
} catch (Exception e) {
System.out.println("[实例化bean失败,名称:" + beanName + "]" + e);
}
}
}
return instance;
}
}
XML解析版
package test;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class BeanFactory {
private Map<String, Object> beanMap = new HashMap<String, Object>();
public void init(String xml) {
try {
// 读取指定的配置文件
SAXReader reader = new SAXReader();
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
// 从class目录下获取指定的xml文件
InputStream ins = classLoader.getResourceAsStream(xml);
Document doc = reader.read(ins);
Element root = doc.getRootElement();
Element foo;
// 遍历bean
for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
foo = (Element) i.next();
// 获取bean的属性id和class
Attribute id = foo.attribute("id");
Attribute cls = foo.attribute("class");
// 利用Java反射机制,通过class的名称获取Class对象
Class bean = Class.forName(cls.getText());
// 获取对应class的信息
java.beans.BeanInfo info = java.beans.Introspector
.getBeanInfo(bean);
// 获取其属性描述
java.beans.PropertyDescriptor pd[] = info
.getPropertyDescriptors();
// 设置值的方法
Method mSet = null;
// 创建一个对象
Object obj = bean.newInstance();
// 遍历该bean的property属性
for (Iterator ite = foo.elementIterator("property"); ite
.hasNext();) {
Element foo2 = (Element) ite.next();
// 获取该property的name属性
Attribute name = foo2.attribute("name");
String value = null;
// 获取该property的子元素value的值
for (Iterator ite1 = foo2.elementIterator("value"); ite1
.hasNext();) {
Element node = (Element) ite1.next();
value = node.getText();
break;
}
for (int k = 0; k < pd.length; k++) {
if (pd[k].getName().equalsIgnoreCase(name.getText())) {
mSet = pd[k].getWriteMethod();
// 利用Java的反射极致调用对象的某个set方法,并将值设置进去 mSet.invoke(obj,
// value);
mSet.invoke(obj, value);
}
}
}
// 将对象放入beanMap中,其中key为id值,value为对象
beanMap.put(id.getText(), obj);
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
public Object getBean(String beanName) {
Object obj = beanMap.get(beanName);
return obj;
}
public static void main(String[] args) {
BeanFactory factory = new BeanFactory();
factory.init("classpath:config.xml");
JavaBean javaBean = (JavaBean) factory.getBean("javaBean");
System.out.println("userName=" + javaBean.getUserName());
System.out.println("password=" + javaBean.getPassword());
}
}