spring深入源码2 简单实现ioc机制 注解形式
上一篇文章 我用了xml形式 实现自己简单版的spring ioc依赖注入 这节主要利用注解形式实现 和上集内容一样 只是加了读取注解的方法。
DAO接口
public interface PersonDao { public void add(); }
实现类
package cn.leam.dao.impl; import cn.leam.dao.PersonDao; public class PersonDaoBean implements PersonDao { public void add(){ System.out.println("执行add()方法"); } }
服务接口
public interface PersonService { public void save(); }
服务实现类
public class PersonServiceBean implements PersonService { @LeamResource private PersonDao personDao; public PersonDao getPersonDao() { return personDao; } public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } public void save(){ personDao.add(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context <!--需要加上注解--> http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!--需要加上注解标签--> <context:annotation-config/> <bean id="personDao" class="cn.leam.dao.impl.PersonDaoBean"></bean> <bean id="personService" class="cn.leam.service.impl.PersonServiceBean"> <!--这里把xml定义的属性去掉 我们使用注解获取 <property name="personDao" ref="personDao"></property> --> </bean> </beans>
下面模拟spring对xml配置的类进行实例化
存放属性的对象
public class prosDefinition { private String name; private String ref; public ProsDefinition(String name, String ref) { this.name = name; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } }
存放bean的 对象
public class Definition { private String id; private String className; private List<ProsDefinition> propertys = new ArrayList<ProsDefinition>(); public Definition(String id, String className) { this.id = id; this.className = className; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<PropertyDefinition> getPropertys() { return propertys; } public void setPropertys(List<PropertyDefinition> propertys) { this.propertys = propertys; } }
加上注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) public @interface LeamResource { public String name() default ""; }
这里是关键点 所有代码都在这里 使用dom4j 解析xml文件中的bean 并获取id和class 再判断元素中是否有引用元素对其一并获取出来存放才Map中 利用java反射一个一个进行实例化
/** * 学习版容器 * */ public class LeamClassPathXMLApplicationContext { private List<Definition> beanDefines = new ArrayList<Definition>(); private Map<String, Object> sigletons = new HashMap<String, Object>(); public LeamClassPathXMLApplicationContext(String filename){ this.readXML(filename); this.instanceBeans(); this.annotationInject(); this.injectObject(); } /** * 为bean对象的属性注入值 */ private void injectObject() { for(Definition beanDefinition : beanDefines){ Object bean = sigletons.get(beanDefinition.getId()); if(bean!=null){ try { PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(ProsDefinition propertyDefinition : beanDefinition.getPropertys()){ for(PropertyDescriptor properdesc : ps){ if(propertyDefinition.getName().equals(properdesc.getName())){ Method setter = properdesc.getWriteMethod();//获取属性的setter方法 if(setter!=null){ Object value = sigletons.get(propertyDefinition.getRef()); setter.setAccessible(true); setter.invoke(bean, value);//把引用对象注入到属性 } break; } } } } catch (Exception e) { } } } } /** * 完成bean的实例化 */ private void instanceBeans() { for(Definition beanDefinition : beanDefines){ try { if(beanDefinition.getClassName()!=null && !"" .equals(beanDefinition.getClassName().trim())) sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } catch (Exception e) { e.printStackTrace(); } } } /** * 读取xml配置文件 * @param filename */ private void readXML(String filename) { SAXReader saxReader = new SAXReader(); Document document=null; try{ URL xmlpath = this.getClass().getClassLoader().getResource(filename); document = saxReader.read(xmlpath); Map<String,String> nsMap = new HashMap<String,String>(); nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间 XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径 xsub.setNamespaceURIs(nsMap);//设置命名空间 List<Element> beans = xsub.selectNodes(document);//获取文档下所有bean节点 for(Element element: beans){ String id = element.attributeValue("id");//获取id属性值 String clazz = element.attributeValue("class"); //获取class属性值 Definition beanDefine = new Definition(id, clazz); XPath propertysub = element.createXPath("ns:property"); propertysub.setNamespaceURIs(nsMap);//设置命名空间 List<Element> propertys = propertysub.selectNodes(element); for(Element property : propertys){ String propertyName = property.attributeValue("name");//元素内部引用的属性也获取 String propertyref = property.attributeValue("ref"); ProsDefinition propertyDefinition = new ProsDefinition(propertyName, propertyref); beanDefine.getPropertys().add(propertyDefinition); } beanDefines.add(beanDefine); } }catch(Exception e){ e.printStackTrace(); } } /** * 获取bean实例 * @param beanName * @return */ public Object getBean(String beanName){ return this.sigletons.get(beanName); } } /** * 通过注解实现注入依赖对象 */ private void annotationInject() { for(String beanName : sigletons.keySet()){ Object bean = sigletons.get(beanName); if(bean!=null){ try { PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor properdesc : ps){ Method setter = properdesc.getWriteMethod();//获取属性的setter方法 //如果是用了注解 将在set方法注入进去 if(setter!=null && setter.isAnnotationPresent(LeamResource.class)){ LeamResource resource = setter.getAnnotation(LeamResource.class); Object value = null; if(resource.name()!=null && !"".equals(resource.name())){ value = sigletons.get(resource.name()); }else{ value = sigletons.get(properdesc.getName()); if(value==null){ for(String key : sigletons.keySet()){ if(properdesc.getPropertyType(). isAssignableFrom(sigletons.get(key).getClass())){ value = sigletons.get(key); break; } } } } setter.setAccessible(true);允许访问私有字段 setter.invoke(bean, value);//把引用对象注入到属性 } } Field[] fields = bean.getClass().getDeclaredFields(); for(Field field : fields){ if(field.isAnnotationPresent(LeamResource.class)){ LeamResource resource = field.getAnnotation(LeamResource.class); Object value = null; if(resource.name()!=null && !"".equals(resource.name())){ value = sigletons.get(resource.name()); }else{ value = sigletons.get(field.getName()); if(value==null){ for(String key : sigletons.keySet()){ if(field.getType(). isAssignableFrom(sigletons.get(key).getClass())){ value = sigletons.get(key); break; } } } } field.setAccessible(true);//允许访问private字段 field.set(bean, value); } } } catch (Exception e) { e.printStackTrace(); } } } }
public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ LeamClassPathXMLApplicationContext ctx = new LeamClassPathXMLApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService"); personService.save(); } }
最终输出
"执行add()方法" 说明实例化成功 否则 出现空指针异常
相关推荐
tianxiaolu 2020-04-06
itjavashuai 2020-07-28
smalllove 2020-07-27
willluckysmile 2020-06-29
TiDBPingCAP 2020-06-21
丽丽 2020-06-11
shenxiuwen 2020-06-10
willluckysmile 2020-06-10
MrFuWen 2020-06-09
yuanye0 2020-06-08
whbing 2020-05-19
yuanye0 2020-05-14
kong000dao0 2020-05-10
方志朋 2020-05-08
somyjun 2020-05-01
suixinsuoyu 2020-04-29
咻pur慢 2020-04-22
吾日五省我身 2020-03-28