软件设计模式期末作业的设计内容:
在网上参考了资料,将两份资料,再加上自己的理解融合成一份!!
xml的参考资料’君君要上天’手写的IOC容器
注解的参考资料’楠哥教你学Java’手写的IOC容器
1.概念
IOC又称控制反转,把原先我们代码里面需要实现的对象的创建、依赖的代码,反转给容器来帮忙实现。
2.设计思路
A.配置文件配置包扫描路径
B.递归包扫描获取.class文件
C.反射确定需要交给IOC管理的类
D.对需要注入的类进行依赖注入
3.XMl配置
3.1导入依赖
dom4j dom4j1.6.1 jaxen jaxen1.1.4 org.projectlombok lombok1.18.10 compile
3.2编写Property
package com.myspring.bean; public class Property { private String name; private String value; private String ref; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } }
3.3编写Bean
package com.myspring.bean; import java.util.ArrayList; import java.util.List; public class Bean { private String beanName; private String className; private Class beanClass; private Listproperties = new ArrayList ();//bean节点下可以有多个property节点 public Bean(){} public Bean(String beanName,Class beanClass){ this.beanName=beanName; this.beanClass=beanClass; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public Class getBeanClass() { return beanClass; } public void setBeanClass(Class beanClass) { this.beanClass = beanClass; } public List getProperties() { return properties; } public void setProperties(List properties) { this.properties = properties; } @Override public String toString() { return "Bean{" + "beanName='" + beanName + ''' + ", className='" + className + ''' + ", beanClass=" + beanClass + ", properties=" + properties + '}'; } }
3.4编写工具类BeanUtil
package com.myspring.utils; import java.lang.reflect.Method; public class BeanUtil { public static Method getSetterMethod(Object obj,String name){ Method method = null; //setter方法名称(驼峰) name = "set"+name.substring(0,1).toUpperCase()+name.substring(1); try { Method[] methods = obj.getClass().getMethods(); //遍历该类的所有方法 for(int i=0;i3.5编写扫描器XmlScanner
package com.myspring.scanner; import com.myspring.bean.Bean; import com.myspring.bean.Property; import org.dom4j.document; import org.dom4j.documentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; public class XmlScanner { public static MapgetBeanMap(String path){ Map beanMap = new HashMap (); //使用dom4j和xpath读取xml文件 //使用SAXReader需要导入dom4j-full.jar包。 //dom4j是一个Java的XML API,用来读写XML文件的。 // 定义一个文档 document doc = null; // 创建xml解析对象 SAXReader reader = new SAXReader(); //getResourceAsStream为读取文件,返回的是inputStream类型的(path传进来的参数) InputStream in = XmlScanner.class.getResourceAsStream(path); try { //xml解析对象对输入流进行解析,解析完放在doc文档中 doc = reader.read(in); } catch (documentException e) { e.printStackTrace(); throw new RuntimeException("请检查您的xml配置文件路径是否正确!"); } //定义xpath,取出所有的bean String xpath = "//bean"; //对bean进行遍历 文档进行选则节点(bean) List list = doc.selectNodes(xpath); //当文件的bean有至少一个,则list!=null if(list!=null){ //for加强循环,把list中的element取出来(bean) for (Element beanEle : list) { //new一个bean对象 Bean bean = new Bean(); //bean节点的id String id = beanEle.attributevalue("id"); //bean节点的class属性 String className = beanEle.attributevalue("class"); //封装到bean对象中 bean.setBeanName(id); bean.setClassName(className); //获取bean节点下所有的property节点(属性) List proList = beanEle.elements("property"); //当bean中的属性对象个数大于0,至少含有一个 if(proList != null){ for (Element pro : proList) { Property prop = new Property(); String propName = pro.attributevalue("name"); String propValue = pro.attributevalue("value"); String propRef = pro.attributevalue("ref"); //封装到property属性中 prop.setName(propName); prop.setValue(propValue); prop.setRef(propRef); bean.getProperties().add(prop); } } //id是不应重复的(如果后注册的一个新Bean与之前注册过的存在重复) if(beanMap.containsKey(id)){ throw new RuntimeException("bean节点ID重复:" + id); } //将bean封装到map中 beanMap.put(id, bean); } } return beanMap; } } 3.6编写BeanFactory
package com.myspring.context; public interface BeanFactory { Object getBean(String beanName); }3.7编写ClassPathXmlApplicationContext
package com.myspring.context; import com.myspring.bean.Bean; import com.myspring.bean.Property; import com.myspring.scanner.XmlScanner; import com.myspring.utils.BeanUtil; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class ClassPathXmlApplicationContext implements BeanFactory { //定义一个IOC容器 private MapiocMap; //定义一个存储Bean的容器 private Map beanMap; public ClassPathXmlApplicationContext(String path){ //初始化IOC容器 iocMap = new HashMap (); //读取配置文件 beanMap = XmlScanner.getBeanMap(path); if(beanMap!=null){ for(Entry entry : beanMap.entrySet()){ String beanId = entry.getKey(); Bean bean = entry.getValue(); //根据bean生成相应的对象 Object object = createBean(bean); iocMap.put(beanId, object); } } } private Object createBean(Bean bean) { String beanId = bean.getBeanName(); String className = bean.getClassName(); Class c = null; Object object = null; try { //根据bean的class属性生成对象--》反射 c = Class.forName(className); } catch (ClassNotFoundException e) { throw new RuntimeException("您配置的class属性不合法:"+className); } try { //该方法调用的是类的无参构造方法 object = c.newInstance(); } catch (Exception e) { throw new RuntimeException("该类缺少一个无参构造方法:"+className); } //将bean的属性封装到对象中 if(bean.getProperties() != null){ for(Property p : bean.getProperties()){ //情况一:配置文件中使用的是value属性注入 if(p.getValue() != null){ //获取属性对应的setter方法 Method getMethod = BeanUtil.getSetterMethod(object,p.getName()); try { //调用set方法注入 getMethod.invoke(object, p.getValue()); } catch (Exception e) { throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName()); } } //情况二:配置文件中使用的是ref属性注入 if(p.getRef() != null){ //获取属性对应的setter方法 Method getMethod = BeanUtil.getSetterMethod(object,p.getName()); //从容器中找到依赖的对象 Object obj = iocMap.get(p.getRef()); if(obj == null){ throw new RuntimeException("没有找到依赖的对象:"+p.getRef()); }else{ //调用set方法注入 try { getMethod.invoke(object, obj); } catch (Exception e) { throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName()); } } } } } return object; } @Override public Object getBean(String beanName) { return iocMap.get(beanName); } } 3.8测试
3.8.1编写Cat类package com.myspring.test; public class Cat { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Cat{" + "name='" + name + ''' + '}'; } }3.8.2编写People类
package com.myspring.test; public class People { private String name; private Cat cat; public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } @Override public String toString() { return "People{" + "name='" + name + ''' + ", cat=" + cat + '}'; } }3.8.3编写ApplicationContext.xml
3.8.4编写Test类
package com.myspring.test; import com.myspring.bean.Bean; import com.myspring.context.BeanFactory; import com.myspring.context.ClassPathXmlApplicationContext; import com.myspring.scanner.XmlScanner; import java.util.Map; public class Test { public static void main(String[] args) { //测试xml BeanFactory factory = new ClassPathXmlApplicationContext("/applicationContext.xml"); People people = (People) factory.getBean("people"); System.out.println(people.toString()); Cat cat = (Cat) factory.getBean("cat"); System.out.println(cat.toString()); } }测试成功!!
4.注解配置【注解所需要的Bean、BeanFactory不需要重写,故注解省略】
4.1编写注解
4.1.1编写注解@Autowiredpackage com.myspring.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }4.1.2编写注解@Component
package com.myspring.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component { String value() default ""; }4.1.3编写注解@Qualifier
package com.myspring.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Qualifier { String value(); }4.1.4编写注解@Value
package com.myspring.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); }4.2编写注解扫描器AnnotationScanner
package com.myspring.scanner; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.URL; import java.net.URLDecoder; import java.util.Enumeration; import java.util.linkedHashSet; import java.util.Set; public class AnnotationScanner { public static Set> getClasses(String pack) { // 第一个class类的集合 Set > classes = new linkedHashSet >(); // 是否循环迭代 boolean flag = true; // 获取包的名字 并进行替换 String packageName = pack; String packageDirName = packageName.replace('.', '/'); // 定义一个枚举的集合 并进行循环来处理这个目录下的things Enumeration dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); // 循环迭代下去 while (dirs.hasMoreElements()) { // 获取下一个元素 URL url = dirs.nextElement(); // 得到协议的名称 String protocol = url.getProtocol(); // 如果是以文件的形式保存在服务器上 if ("file".equals(protocol)) { // 获取包的物理路径 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 以文件的方式扫描整个包下的文件 并添加到集合中 findByFile(packageName, filePath, flag, classes); } } } catch (IOException e) { e.printStackTrace(); } return classes; } private static void findByFile(String packageName, String packagePath, final boolean flag, Set > classes) { // 获取此包的目录 建立一个File File dir = new File(packagePath); // 如果不存在或者 也不是目录就直接返回 if (!dir.exists() || !dir.isDirectory()) { return; } // 如果存在 就获取包下的所有文件 包括目录 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) @Override public boolean accept(File file) { return (flag && file.isDirectory()) || (file.getName().endsWith(".class")); } }); // 循环所有文件 for (File file : dirfiles) { // 如果是目录 则继续扫描 if (file.isDirectory()) { findByFile(packageName + "." + file.getName(), file.getAbsolutePath(), flag, classes); } else { // 如果是java类文件 去掉后面的.class 只留下类名 String className = file.getName().substring(0, file.getName().length() - 6); try { // 添加到集合中去 classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } } 4.3编写AnnotationApplicationContext
package com.myspring.context; import com.myspring.annotation.Autowired; import com.myspring.annotation.Component; import com.myspring.annotation.Qualifier; import com.myspring.annotation.Value; import com.myspring.bean.Bean; import com.myspring.scanner.AnnotationScanner; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; public class AnnotationApplicationContext implements BeanFactory { private MapiocMap = new HashMap<>(); private List beanNames = new ArrayList<>(); public AnnotationApplicationContext(String pack) { //遍历包,找到目标类(原材料) Set bean = findBean(pack); //根据原材料创建bean createObject(bean); //自动装载 autowireObject(bean); } public void autowireObject(Set bean){ Iterator iterator = bean.iterator(); while (iterator.hasNext()) { Bean beanDefinition = iterator.next(); Class clazz = beanDefinition.getBeanClass(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { Autowired annotation = declaredField.getAnnotation(Autowired.class); if(annotation!=null){ Qualifier qualifier = declaredField.getAnnotation(Qualifier.class); if(qualifier!=null){ //byName try { String beanName = qualifier.value(); Object beanOb = getBean(beanName); String fieldName = declaredField.getName(); String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); Method method = clazz.getMethod(methodName, declaredField.getType()); Object object = getBean(beanDefinition.getBeanName()); method.invoke(object, beanOb); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } } } public Object getBean(String beanName){ return iocMap.get(beanName); } public String[] getBeanNames(){ return beanNames.toArray(new String[0]); } public Integer getBeanCount(){ return beanNames.size(); } public void createObject(Set bean){ Iterator iterator = bean.iterator(); while (iterator.hasNext()) { Bean beanDefinition = iterator.next(); Class clazz = beanDefinition.getBeanClass(); String beanName = beanDefinition.getBeanName(); try { //创建的对象 Object object = clazz.getConstructor().newInstance(); //完成属性的赋值 Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { Value valueAnnotation = declaredField.getAnnotation(Value.class); if(valueAnnotation!=null){ String value = valueAnnotation.value(); String fieldName = declaredField.getName(); String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); Method method = clazz.getMethod(methodName,declaredField.getType()); //完成数据类型转换 Object val = null; switch (declaredField.getType().getName()){ case "java.lang.Integer": val = Integer.parseInt(value); break; case "java.lang.String": val = value; break; case "java.lang.Float": val = Float.parseFloat(value); break; } method.invoke(object, val); } } //存入缓存 iocMap.put(beanName, object); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } public Set findBean(String pack){ //1、获取包下的所有类 Set > classes = AnnotationScanner.getClasses(pack); Iterator > iterator = classes.iterator(); Set bean = new HashSet<>(); while (iterator.hasNext()) { //2、遍历这些类,找到添加了注解的类 Class> clazz = iterator.next(); Component componentAnnotation = clazz.getAnnotation(Component.class); if(componentAnnotation!=null){ //获取Component注解的值 String beanName = componentAnnotation.value(); if("".equals(beanName)){ //获取类名首字母小写 String className = clazz.getName().replaceAll(clazz.getPackage().getName() + ".", ""); beanName = className.substring(0, 1).toLowerCase()+className.substring(1); } //3、将这些类封装成BeanDefinition,装载到集合中 bean.add(new Bean(beanName, clazz)); beanNames.add(beanName); } } return bean; } } 4.4测试
4.4.1编写Book类package com.myspring.test; import com.myspring.annotation.Component; import com.myspring.annotation.Value; import lombok.Data; @Component //@Data public class Book { @Value("BOOK1001") private String id; @Value("软件设计模式") private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Book{" + "id='" + id + ''' + ", name='" + name + ''' + '}'; } }4.4.2编写Student类
package com.myspring.test; import com.myspring.annotation.Autowired; import com.myspring.annotation.Component; import com.myspring.annotation.Qualifier; import com.myspring.annotation.Value; @Component public class Student { @Value("小红") private String name; @Value("18") private Integer age; @Autowired @Qualifier("book") private Book book; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Student{" + "name='" + name + ''' + ", age=" + age + ", book=" + book + '}'; } }4.4.3编写Test类
package com.myspring.test; import com.myspring.bean.Bean; import com.myspring.context.AnnotationApplicationContext; import com.myspring.context.BeanFactory; import java.util.Map; public class Test { public static void main(String[] args) { //测试注解 BeanFactory factory1 = new AnnotationApplicationContext("com.myspring.test"); Student student = (Student) factory1.getBean("student"); System.out.println(student); Book book = (Book) factory1.getBean("book"); System.out.println("book->"+book.toString()); } }测试成功!!
有需要可以找我要源码!!侵权私聊删!!欢迎分享,转载请注明来源:内存溢出
评论列表(0条)