IOC控制反转就是经过反射机制帮咱们托管了全部的类。
我想要本身实现的就是使用XML注入Bean和使用注解(@Service
之类的)注入Bean安全
SpringIOC的XML版本使用Dom4j和反射技术解析XML和注入类
全部的Bean在ApplicationContext建立的时候就会初始化bash
一个本身解析XML的小Demo,使用Dom4j解析XML,以下app
public class XmlUtils {
public static void main(String[] args) throws DocumentException {
XmlUtils xmlUtils = new XmlUtils();
xmlUtils.readXml("student.xml");
}
public void readXml(String xmlPath) throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(getResourceAsSteam(xmlPath));
Element rootElement = document.getRootElement();
getNodes(rootElement);
}
private static void getNodes(Element rootElement) {
//获取节点名称
System.out.print("节点名称:" + rootElement.getName()+"\t\t");
//获取节点属性
List<Attribute> attributes = rootElement.attributes();
for (Attribute attribute : attributes) {
System.out.print("属性:"+attribute.getName()+"---"+attribute.getText()+"\t\t");
}
//获取属性值
String value = rootElement.getTextTrim();
if (!StringUtils.isEmpty(value)) {
System.out.print("节点值:" + value+"\t\t");
}
System.out.println();
//遍历子节点
Iterator<Element> elementIterator = rootElement.elementIterator();
while (elementIterator.hasNext()) {
Element next = elementIterator.next();
getNodes(next);
}
}
private InputStream getResourceAsSteam(String xmlPath) {
return this.getClass().getClassLoader().getResourceAsStream(xmlPath);
}
}
复制代码
/** 用于GetBean的方法*/
public Object getBean(String beanId) throws DocumentException, IllegalAccessException, InstantiationException, ClassNotFoundException {
if (StringUtils.isEmpty(beanId)) {
throw new RuntimeException("BeanId为空");
}
//解析Xml,获取全部节点
List<Element> elements = readXml();
if (elements == null||elements.isEmpty()) {
throw new RuntimeException("没有任何Bean信息");
}
//查找对应的ClassName
String className = getClassName(beanId, elements);
if (StringUtils.isEmpty(className)) {
throw new RuntimeException("没有配置类信息");
}
//利用反射机制建立Bean
return newInstance(className);
}
复制代码
全文以下工具
public class ExtClassPathXmlApplicationContext {
private String xmlPath;
public ExtClassPathXmlApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
}
/** 用于GetBean的方法*/
public Object getBean(String beanId) throws DocumentException, IllegalAccessException, InstantiationException, ClassNotFoundException {
if (StringUtils.isEmpty(beanId)) {
throw new RuntimeException("BeanId为空");
}
//解析Xml,获取全部节点
List<Element> elements = readXml();
if (elements == null||elements.isEmpty()) {
throw new RuntimeException("没有任何Bean信息");
}
//查找对应的ClassName
String className = getClassName(beanId, elements);
if (StringUtils.isEmpty(className)) {
throw new RuntimeException("没有配置类信息");
}
//利用反射机制建立Bean
return newInstance(className);
}
/**解析Xml文件,获取全部节点*/
private List<Element> readXml() throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(getResourceAsSteam());
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
return elements;
}
}
复制代码
而后在主方法里建立上面的Context,使用getBean方法,就能够拿到想要的Bean了(和Spring的ClassPathApplicationContext同样)ui
/**初始化Bean容器*/
private void initBeans() throws IllegalAccessException, InstantiationException {
beans = new ConcurrentHashMap<String, Object>();
//使用扫包工具得到包下全部的类
List<Class<?>> classes = ClassUtils.getClasses(packageName);
//判断全部的类上面是否有注解,有的话就会加入到Bean容器里面去
findClassExistAnnotation(classes);
if (beans == null || beans.isEmpty()) {
throw new RuntimeException("没有类加上了注解");
}
}
复制代码
全文以下this
public class ExtAnnotationApplicationContext {
private String packageName;
/**保存有Service注解的类*/
private ConcurrentHashMap<String, Object> beans = null;
public ExtAnnotationApplicationContext(String packageName) throws InstantiationException, IllegalAccessException {
this.packageName = packageName;
initBeans();
}
/**初始化Bean容器*/
private void initBeans() throws IllegalAccessException, InstantiationException {
beans = new ConcurrentHashMap<String, Object>();
//使用扫包工具得到包下全部的类
List<Class<?>> classes = ClassUtils.getClasses(packageName);
//判断全部的类上面是否有注解,有的话就会加入到Bean容器里面去
findClassExistAnnotation(classes);
if (beans == null || beans.isEmpty()) {
throw new RuntimeException("没有类加上了注解");
}
}
/**扫包,把有注解的类加入到bean容器里*/
private void findClassExistAnnotation(List<Class<?>> classes) throws InstantiationException, IllegalAccessException {
for (Class classInfo : classes) {
//判断是否有注解
Annotation annotation = classInfo.getAnnotation(ExtService.class);
if (annotation != null) {
//到这里表示有这个注解
String className = classInfo.getName();
//默认Id是首字母小写
beans.put(toLowerCaseFirestOne(classInfo.getSimpleName()), newInstance(classInfo));
}
}
}
/**类名的首字母小写*/
private String toLowerCaseFirestOne(String className) {
return new StringBuilder().append(Character.toLowerCase(className.charAt(0))).append(className.substring(1)).toString();
}
/**获取Bean的方法*/
public Object getBean(String beanId) throws IllegalAccessException, InstantiationException {
if (StringUtils.isEmpty(beanId)) {
throw new RuntimeException("BeanID为空");
}
return beans.get(beanId);
}
/**利用反射机制建立Bean*/
private Object newInstance(Class classInfo) throws IllegalAccessException, InstantiationException {
if (classInfo == null) {
throw new RuntimeException("没有这个ID的bean");
}
return classInfo.newInstance();
}
/**依赖注入传入类的属性*/
private void attrAssign(Class<?> classInfo) {
//获取这个类全部的属性
Field[] fields = classInfo.getFields();
//判断当前属性是否有注解
for (Field field : fields) {
ExtService extService = field.getAnnotation(ExtService.class);
if (extService != null) {
//到这里说明这个属性里有这个注解
String fieldName = field.getName();
}
}
}
}
复制代码
如今获取到Bean只用在类上加上本身的Service注解而后使用getBean方法传入类名的首字母小写就能够了spa
/**自动注入注入这个对象的属性*/
private void attrAssign(Object object) throws IllegalAccessException {
//获取这个类全部的属性
Field[] fields = object.getClass().getDeclaredFields();
//判断当前属性是否有注解
for (Field field : fields) {
ExtService extService = field.getAnnotation(ExtService.class);
if (extService != null) {
//到这里说明这个属性里有这个注解,在从容器里获取对象而后给这个属性赋值
String fieldName = field.getName();
Object target = beans.get(fieldName);
if (target == null) {
throw new RuntimeException("注入\"" + fieldName + "\"属性失败,bean容器里没有这个对象");
}
//容许访问私有属性
field.setAccessible(true);
//第一个参数是这个属性所在的对象
field.set(object,target);
}
}
}
复制代码
这个方法咱们须要在Bean容器初始化完成以后,把全部的bean容器的Object里作一遍,达到依赖注入的效果,以下(若是给全部的类都实现注入Bean容器里的bean的话,就是依赖注入@Autowired
了)线程
public ExtAnnotationApplicationContext(String packageName) throws InstantiationException, IllegalAccessException {
this.packageName = packageName;
initBeans();
//在全部Bean容器里全部bean自动注入全部的Bean
for (Map.Entry<String, Object> entry : beans.entrySet()) {
System.out.println("beanId:"+entry.getKey());
Object bean = entry.getValue();
attrAssign(bean);
}
}
复制代码
增长了依赖注入的Context全文以下rest
public class ExtAnnotationApplicationContext {
private String packageName;
/**保存有Service注解的类*/
private ConcurrentHashMap<String, Object> beans = null;
public ExtAnnotationApplicationContext(String packageName) throws InstantiationException, IllegalAccessException {
this.packageName = packageName;
initBeans();
//在全部Bean容器里全部bean自动注入全部的Bean
for (Map.Entry<String, Object> entry : beans.entrySet()) {
System.out.println("beanId:"+entry.getKey());
Object bean = entry.getValue();
attrAssign(bean);
}
}
/**初始化Bean容器*/
private void initBeans() throws IllegalAccessException, InstantiationException {
beans = new ConcurrentHashMap<String, Object>();
//使用扫包工具得到包下全部的类
List<Class<?>> classes = ClassUtils.getClasses(packageName);
//判断全部的类上面是否有注解,有的话就会加入到Bean容器里面去
findClassExistAnnotation(classes);
if (beans == null || beans.isEmpty()) {
throw new RuntimeException("没有类加上了注解");
}
}
/**扫包,把有注解的类加入到bean容器里*/
private void findClassExistAnnotation(List<Class<?>> classes) throws InstantiationException, IllegalAccessException {
for (Class classInfo : classes) {
//判断是否有注解
Annotation annotation = classInfo.getAnnotation(ExtService.class);
if (annotation != null) {
//到这里表示有这个注解
String className = classInfo.getName();
//默认Id是首字母小写
beans.put(toLowerCaseFirestOne(classInfo.getSimpleName()), newInstance(classInfo));
}
}
}
/**类名的首字母小写*/
private String toLowerCaseFirestOne(String className) {
return new StringBuilder().append(Character.toLowerCase(className.charAt(0))).append(className.substring(1)).toString();
}
/**获取Bean的方法*/
public Object getBean(String beanId) throws IllegalAccessException, InstantiationException {
if (StringUtils.isEmpty(beanId)) {
throw new RuntimeException("BeanID为空");
}
return beans.get(beanId);
}
/**利用反射机制建立Bean*/
private Object newInstance(Class classInfo) throws IllegalAccessException, InstantiationException {
if (classInfo == null) {
throw new RuntimeException("没有这个ID的bean");
}
return classInfo.newInstance();
}
/**自动注入注入这个对象的属性*/
private void attrAssign(Object object) throws IllegalAccessException {
//获取这个类全部的属性
Field[] fields = object.getClass().getDeclaredFields();
//判断当前属性是否有注解
for (Field field : fields) {
ExtResource extResource = field.getAnnotation(ExtResource.class);
if (extResource != null) {
//容许访问私有属性
field.setAccessible(true);
//到这里说明这个属性里有这个注解,在从容器里获取对象而后给这个属性赋值
String fieldName = field.getName();
Object target = beans.get(fieldName);
if (target == null) {
throw new RuntimeException("注入\"" + fieldName + "\"属性失败,bean容器里没有这个对象");
}
//第一个参数是这个属性所在的对象
field.set(object,target);
}
}
}
}
复制代码