`
8366
  • 浏览: 821032 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

第12讲 --编码剖析@Resource注解的实现原理

阅读更多

 

在这一讲开始之前,我们先学习一下jdk5.0 中的一个新特性: 注解

首先转载两篇文章:

 

J2SE5.0中新特性:注释 

 

设计自己的Annotation Java

 

 

如果使用了JSR-250中的注解,如@Resource/@PostConstruct/@PreDestroy,还需要下列jar文件
lib\j2ee\common-annotations.jar

 

 

下面我们继续改造我们自己实现的spring容器 (传智播客版spring容器)ItcastClassPathXMLApplicationContext.,完成类似的使用注解完成依赖对象的注入

 

 

步骤:

(1)首先创建一个自己的注解 ItcastResource ,类似上一讲的 Resource注解

 

package junit.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ItcastResource {
	public String name() default ""; //注解的默认name值是""
}

 

 

@Retention(RetentionPolicy.RUNTIME)

RUNTIME表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的

 

@Target({ElementType.FIELD, ElementType.METHOD})

 

@Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的.说明一下:TYPE(类型), FIELD(属性), METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量), ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和Annotation类型上.

 

(2)将 PersionServiceBean 中的Resource注解 换成我们自己的 ItcastResource 注解

 

 

(3) 修改仿spring容器 ,也就是传智播客容器 ItcastClassPathXMLApplicationContext

 

package junit.test;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
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.apache.commons.beanutils.ConvertUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

/**
 * 传智传客版容器
 *
 */
public class ItcastClassPathXMLApplicationContext {
	private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
	private Map<String, Object> sigletons = new HashMap<String, Object>();
	
	public ItcastClassPathXMLApplicationContext(String filename){
		this.readXML(filename);
		this.instanceBeans();
		this.annotationInject();
		this.injectObject();
	}
	/**
	 * 通过注解实现注入依赖对象
	 */
	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方法
						/*如果setter方法不为空,并且上面有注解*/
						if(setter!=null && setter.isAnnotationPresent(ItcastResource.class)){
							/*得到注解*/
							ItcastResource resource = setter.getAnnotation(ItcastResource.class);
							Object value = null;
							//如果注解的name属性不为空,也就是这种情况	@ItcastResource(name="persionDao")
							if(resource.name()!=null && !"".equals(resource.name())){
								value = sigletons.get(resource.name());
							}else{
							/*如果注解的name为空,则根据属性的名字来得到bean*/
								value = sigletons.get(properdesc.getName());
								if(value==null)
								{
									/*如果的得到的bean为空,则根据key遍历容器中所有的bean,如果发现和属性类型相同的bean,就开始注入*/
									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(ItcastResource.class)){
							ItcastResource resource = field.getAnnotation(ItcastResource.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();
				}
			}
		}
	}

	/**
	 * 为bean对象的属性注入值
	 */
	private void injectObject() {
		for(BeanDefinition beanDefinition : beanDefines){
			Object bean = sigletons.get(beanDefinition.getId());
			if(bean!=null){
				try {
					PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
					for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys()){
						for(PropertyDescriptor properdesc : ps){
							if(propertyDefinition.getName().equals(properdesc.getName())){
								Method setter = properdesc.getWriteMethod();//获取属性的setter方法 ,private
								if(setter!=null){
									Object value = null;
									if(propertyDefinition.getRef()!=null && !"".equals(propertyDefinition.getRef().trim())){
										value = sigletons.get(propertyDefinition.getRef());
									}else{
										value = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType());
									}
									setter.setAccessible(true);
									setter.invoke(bean, value);//把引用对象注入到属性
								}
								break;
							}
						}
					}
				} catch (Exception e) {
				}
			}
		}
	}
	/**
	 * 完成bean的实例化
	 */
	private void instanceBeans() {
		for(BeanDefinition 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属性值        
	            BeanDefinition beanDefine = new BeanDefinition(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");
	            	String propertyValue = property.attributeValue("value");
	            	PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref, propertyValue);
	            	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);
	}
}

 

 

 

 (4) 测试 将@ItcastResource(name="persionDao") 放在字段或者相应的setter方法上两种情况

 

ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml");
  PersionSevice ps=(PersionSevice)ctx.getBean("persionServiceBean");
  ps.save();


 (5)结果

INFO (PersionServiceBean.java:19) - 我被实例化了

INFO (PersionDaoBean.java:15) - 执行了PersionDaoBean中的add()方法

 

分享到:
评论
1 楼 laijavatoo 2012-05-10  
这个太难了

相关推荐

    @Conditional注解应用.rar

    在Java Spring框架中,`@Conditional`注解是实现条件化bean注入的关键工具。这个注解允许我们在配置bean时设置一些条件,只有当这些条件满足时,对应的bean才会被Spring容器实例化并注入到应用程序中。这样的设计极...

    @ConfigurationProperties注解使用方法(源代码)

    1.2 第二阶段:注解配置 1.3 第三阶段:Java配置(java config) 二、@ConfigurationProperties使用方法 三、使用场景 3.1 作用于方法 3.1.1 使用场景(`配置读写分离`) 3.1.2 读写分离 案例实操 3.1.2.1 数据库的...

    如何使用Spring Boot的@Pointcut注解

    #### 第二部分:@Pointcut注解详解 1. **@Pointcut注解使用** - **方法级别**:@Pointcut注解通常用于定义具体的切点表达式。例如,可以通过`@Pointcut("execution(* com.example.demo.service.*.*(..))")`定义一...

    LTE系统中Reed-Muller码的编码研究与实现

    在“LTE系统中Reed-Muller码的编码研究与实现”这篇毕业设计中,作者可能详细介绍了Reed-Muller码的理论背景,分析了其在LTE环境下的性能优势,并给出了具体的软件或硬件实现方案。可能还包含了对不同级别Reed-...

    AMR-NB 与 AMR-WB 语音编码标准技术的对比研究

    ### AMR-NB与AMR-WB语音编码标准技术的深度对比 #### 一、引言与背景 自适应多速率语音编码技术是现代通信领域的重要组成部分,旨在提高语音通信的质量与效率。其中,AMR-NB(Adaptive Multi-Rate Narrow Band ...

    VHDL语言描述8-3优先编码器

    具体实现时,可以考虑将第一个8-3优先编码器的输出作为第二个编码器的部分输入,从而实现对16个输入信号的编码。 #### 六、总结 本文详细介绍了如何使用VHDL语言实现一个8-3优先编码器,并对其工作原理进行了深入...

    基于Matlab对MIMO通信系统中的3大部分-空时编码、系统容量、信道估计进行仿真分析项目源码-毕设

    基于Matlab对MIMO通信系统中的3大部分-空时编码、系统容量、信道估计进行仿真分析项目源码-毕设,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定...

    springboot整合es-springboot-elasticsearch.zip

    SpringBoot整合Elasticsearch是现代Java开发中常见的一项任务,因为SpringBoot的便捷性和Elasticsearch的高效搜索能力,使得这种结合在数据检索、分析和日志存储等领域广泛应用。本项目"springboot-elasticsearch-...

    Android自定义注解实现View绑定Demo

    实现自定义注解的第一步是定义注解类。例如: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface BindView { int value(); } ``` 这里,`@Retention(RetentionPolicy....

    第三节-springboot源码解析-王炸篇.pdf

    Spring Boot源码解析是深入了解Spring Boot内部工作原理和机制的重要途径。通过源码分析,开发者可以更好地理解Spring Boot的自动装配、启动流程以及如何自定义启动器。Spring Boot的自动装配原理涉及到Spring Boot...

    基于Matlab对MIMO通信系统中的3大部分-空时编码、系统容量和信道估计进行仿真分析源码+说明(高分毕设)

    基于Matlab对MIMO通信系统中的3大部分-空时编码、系统容量和信道估计进行仿真分析源码+说明(高分毕设),个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以...

    基于C语言的GBK-Unicode文本编码转换系统的实现.pdf

    总结来说,本文通过分析并实现了基于C语言的GBK-Unicode文本编码转换系统,详细阐述了GBK和Unicode编码的原理、两者之间的映射关系以及转换过程中的字节序标记问题,提供了通过C语言操作映射表实现编码转换的方法,...

    gb2312-80编码表

    其编码范围是从A1A1到FEFE(十六进制表示),即从161×161到254×254(十进制表示)。整个编码空间被分为94×94=8836个区位,每个区位可以存放一个汉字或符号。 #### 三、具体编码规则 GB2312-80编码表分为以下几个...

    EC16-YJ 编码器 使用时序图

    在深入探讨EC16-YJ编码器的使用时序图之前,我们首先应当明确编码器的基本概念及其在现代工业自动化、机器人技术以及精密控制领域的应用价值。编码器是一种传感器,用于测量并转换物理位置或运动到电信号,这些信号...

    Java企业级信息系统开发学习笔记

    第 13 篇 Java 企业级信息系统开发学习笔记(4.2)Spring Boot 项目单元测试、热部署与原理分析 * 了解了如何使用 Spring Boot 项目单元测试 * 学习了如何使用 @RunWith 注解创建单元测试 * 了解了如何使用 @...

    编译原理课程设计---java实现算符优先分析法

    在编译原理中,算符优先分析法是一种用于解析程序语法结构的方法,它基于算符的优先级和结合性来构建语法分析表。本课程设计是关于如何使用Java语言实现这个算法,这对于理解和掌握编译器构造有重要的实践意义。 ...

    基于Java配置类与注解相结合的方式配置Spring IoC容器

    1. Spring IoC容器的工作原理,它如何实现控制反转,以及依赖注入的过程。 2. @Configuration注解的使用,它是如何让Spring识别一个类作为配置类,以及其与@Component注解的区别。 3. @Bean注解的作用,如何通过该...

    JAVA注解(Annotation).doc

    - 注解可以应用于类、方法、变量等,为编译器、构建工具或运行时系统提供额外的信息,例如Spring框架中的依赖注入就是通过注解实现的。 7. **注解的限制** - 同一类型的注解在同一域中只能注解一次。 - 注解不能...

    多媒体技术标准试验报告-1行程编码的解压缩算法实现.doc

    【多媒体技术标准试验报告——1行程编码的解压缩算法实现】 行程编码是一种简单而有效的无损数据压缩算法,尤其适用于处理包含大量重复字符的数据。在本实验中,目的是通过理解和应用行程编码,采用高级编程语言...

Global site tag (gtag.js) - Google Analytics