Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
2017-03-14 15:33
811 查看
注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
手工装配依赖对象
手工装配依赖对象,在这种方式中又有两种编程方式
在xml配置文件中,通过在bean节点下配置,上边博客已经讲解,再次不在缀余。
在java代码中使用@Autowired或@Resource注解方式进行装配。但我们需要在xml配置文件中配置以下信息:
PS:
这个配置隐式注册了多个对注解进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
PS:之前我写过注解原理的博客,再此多说一句,注解本身和xml一样都是用于配置的,本身并不能干活,它之所以能干活,是因为它背后存在着处理器(也就是对应api)。
PS: 需要引入common-annotations.jar文件。
@Autowired和@Resource注解详解
在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Resource注解和@Autowired一样,也可以标注在字段或属性的setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
PS:@Resource在jdk中已经存在,不属于Spring,所以尽量使用这个注解。
编码剖析@Resource的原理:
自定义注解(模仿@Resource):
PersonSevicebean:
自定义注解(zmcResource)处理器:
Java
手工装配依赖对象
手工装配依赖对象,在这种方式中又有两种编程方式
在xml配置文件中,通过在bean节点下配置,上边博客已经讲解,再次不在缀余。
在java代码中使用@Autowired或@Resource注解方式进行装配。但我们需要在xml配置文件中配置以下信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <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/> </beans> |
1 | <context:annotation-config/> |
PS:之前我写过注解原理的博客,再此多说一句,注解本身和xml一样都是用于配置的,本身并不能干活,它之所以能干活,是因为它背后存在着处理器(也就是对应api)。
PS: 需要引入common-annotations.jar文件。
@Autowired和@Resource注解详解
在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
1 2 3 4 5 6 | @Autowired private PersonDao personDao;//用于字段上 @Autowired public void setOrderDao(OrderDao orderDao) {//用于属性的setter方法上 this.orderDao = orderDao; } |
1 2 | @Autowired @Qualifier("personDaoBean") private PersonDao personDao; |
1 2 | @Resource(name=“personDaoBean”) private PersonDao personDao;//用于字段上 |
PS:@Resource在jdk中已经存在,不属于Spring,所以尽量使用这个注解。
编码剖析@Resource的原理:
自定义注解(模仿@Resource):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package zmcSpring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.dom4j.Element; /* * 现在没法工作,只是一些配置信息 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.METHOD}) public @interface zmcResource { public String name() default ""; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package zmc; import dao.PersonDao; import zmcSpring.zmcResource; import zmcjk.PersonService; public class PersonServicebean implements PersonService { private String name; private PersonDao personDao ; public PersonServicebean(){ } public PersonServicebean(String name, PersonDao personDao) { super(); this.name = name; this.personDao = personDao; } public String getName() { return name; } public void setName(String name) { this.name = name; } public PersonDao getPersonDao() { return personDao; } @zmcResource public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } public void save(){ personDao.add(); } } |
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | package zmcSpring; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; /* * 简单模拟Spring容器 */ public class ZmcClassPathXMLApplicationContext { private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>(); private Map<String,Object> sigletons = new HashMap<String,Object>(); public ZmcClassPathXMLApplicationContext(String fileName){ this.readXML(fileName); this.instanceBeans(); this.annotationInject(); this.injectObject();//依赖注入 } /* * 暂且把zmcResouce处理器写在这里 */ 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方法 Object obj = null; if(setter!=null&&setter.isAnnotationPresent(zmcResource.class)){//判断是否存在zmcResource注解 zmcResource zmc = setter.getAnnotation(zmcResource.class); if(zmc.name()!=null&&!"".equals(zmc.name())){ obj = sigletons.get(zmc.name()); }else{//没有设置name属性,即取得属性名称 obj = sigletons.get(properdesc.getName()); if(obj==null){//这时按类型 for(String beanname: sigletons.keySet()){ if(properdesc.getPropertyType().isAssignableFrom(sigletons.get(beanname).getClass())){//两者类型是否匹配,前者类型是否是后者的父类或接口 obj=sigletons.get(beanname); break; } } } } setter.invoke(bean, obj); } } Field[] fileds = bean.getClass().getDeclaredFields(); for(Field field : fileds){ if(field.isAnnotationPresent(zmcResource.class)){ zmcResource zmc =field.getAnnotation(zmcResource.class); Object obj = null; if(zmc.name()!=null&&!"".equals(zmc.name())){ obj = sigletons.get(zmc.name()); }else{ obj = sigletons.get(field.getName()); if(obj==null){ for(String key : sigletons.keySet()){ if(field.getType().isAssignableFrom(sigletons.get(key).getClass())){ obj = sigletons.get(key); break; } } } } field.setAccessible(true); field.set(bean, obj); } } } catch (Exception e){ e.printStackTrace(); } } } } /* * 为bean属性注入值 */ private void injectObject() { for(BeanDefinition beanDefinition : beanDefines){ Object bean = sigletons.get(beanDefinition.getId());//此时bean还没有注入 //下面开始进行依赖注入 if(bean!=null){ //取得bean的属性描述 try { PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();//bean的属性 for(PropertyDefinition propertyDefinition : beanDefinition.getProperty()){//用户配置文件中定义的属性 for(PropertyDescriptor properdesc : ps){ //判断配置文件中属性的名称和bean中属性的名称是否相同 if(propertyDefinition.getName().equals(properdesc.getName())){ Method setter = properdesc.getWriteMethod(); if(setter!=null){ if(propertyDefinition.getRef()!=null&&!"".equals(propertyDefinition.getRef().trim())){ Object value = sigletons.get(propertyDefinition.getRef()); try { setter.invoke(bean, value); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); }//把引用对象注入到属性 } } } } } } catch (IntrospectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /* * 完成bean的实例化 */ private void instanceBeans(){ for(BeanDefinition beanDefinition : beanDefines){ try { sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /* * 读取XMl配置文件 * @param filename */ public 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); for(Element element : beans){ String id = element.attributeValue("id"); String clazz = element.attributeValue("class"); BeanDefinition beanDefinition = new BeanDefinition(id,clazz); XPath propertysub = element.createXPath("ns:property");//nodename(节点名称):表示选择该节点的所有子节点 propertysub.setNamespaceURIs(nsMap); List<Element> propertys = propertysub.selectNodes(element); for(Element property:propertys){ String propertyName = property.attributeValue("name"); String propertyRef = property.attributeValue("ref"); String propertyValue = property.attributeValue("value"); PropertyDefinition pd = new PropertyDefinition(propertyName, propertyRef,propertyValue); beanDefinition.getProperty().add(pd); } beanDefines.add(beanDefinition); } } catch (Exception e){ e.printStackTrace(); } } /* * 获取bean实例 */ public Object getBean(String beanName){ return this.sigletons.get(beanName); } } |
相关文章推荐
- (6) 用@Resource注解完成属性装配 【依赖注入----手动装配】 以及 编码解析其原理【经典】
- (7) 用@Resource注解完成属性装配 【依赖注入----手动装配】 以及 编码解析其原理【经典】
- (5) 编码剖析Spring装配基本属性的原理【附加:注入依赖对象的两种方式】
- (4) 编码剖析Spring装配基本属性的原理【附加:注入依赖对象的两种方式】
- (4) 利用 Setter方式实现 【第一种方式】 依赖注入,编码剖析Spring依赖注入的原理
- spring 依赖注入注解配置原理解析
- (3) 利用 Setter方式实现 【第一种方式】 依赖注入,编码剖析Spring依赖注入的原理
- 传智播客Spring2.5视频教程_编码剖析Spring依赖注入的原理 4
- ITCAST视频-Spring学习笔记(编码剖析@Resource注解的实现原理)
- Spring 编码剖析@Resource注解的实现原理
- SSH深度历险(八) 剖析SSH核心原理+Spring依赖注入的三种方式
- spring通过注解依赖注入和获取xml配置混合的方式
- 有关spring的依赖注入和@resource注解的使用
- Spring IOC 依赖注入的两种方式:XML和注解
- 传智播客Spring2.5视频教程_编码剖析Spring依赖注入的原理 1
- spring学习笔记整理--05(编码剖析Spring依赖注入的原理)
- 编码模拟Spring依赖注入原理
- 传智播客Spring2.5视频教程_编码剖析Spring依赖注入的原理 3
- 传智播客Spring2.5视频教程_编码剖析Spring依赖注入的原理 2
- 编码实现Spring 利用@Resource注解实现bean的注入,xml实现基本数据类型的注入