模拟Spring容器管理bean(Itcast)和注解注入原理

package junit.test;

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.InvalidXPathException;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

public class ItcastClassPathXMLApplicationContext {
	private List<BeanDefinition> beanDefines=new ArrayList<BeanDefinition>();
	private Map<String,Object> singtions=new HashMap<String,Object>();
	public ItcastClassPathXMLApplicationContext(String filename){
		this.readXML(filename);
		instanceBeans();
	}
	
	private void instanceBeans(){
		for(BeanDefinition bd:beanDefines){
			try {
				if(bd.getId()!=null || bd.getClassName()!=null)
				singtions.put(bd.getId(), Class.forName(bd.getClassName()).newInstance());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	@SuppressWarnings({ "null", "unused", "unchecked" })
	private void readXML(String filename) {
		System.out.println("read"+filename);
		SAXReader saxReader=new SAXReader();
		Document document=null;
		try {
			URL xmlPath=this.getClass().getClassLoader().getResource(filename);
//			System.out.println(xmlPath);
			document = saxReader.read(xmlPath);
			
			Map<String, String> nsMap=new HashMap<String, String>();
			nsMap.put("ns","http://www.springframework.org/schema/beans");   //加入命名空间
			System.out.println(nsMap+"nsmap");
			XPath xsub = document.createXPath("//ns:beans/ns:bean");    //创建beans/bean查询路径
			System.out.println("xsub"+xsub);
			xsub.setNamespaceURIs(nsMap);   //设置命名空间
			List<Element> beans=xsub.selectNodes(document);
			for(Element e:beans){
				String id=e.attributeValue("id");         //获取id属性
				String clazz=e.attributeValue("class");   //获取class属性
				BeanDefinition beanDefine=new BeanDefinition(id,clazz);
				beanDefines.add(beanDefine);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public Object getBean(String beanName){
		return singtions.get(beanName);
	}
}

 

package cn.itcast.service.impl;

import cn.itcast.service.IPersonService;

public class PersonServiceBean implements IPersonService {
	/* (non-Javadoc)
	 * @see cn.itcast.service.impl.IPersonService#save()
	 */
	@Override
	public void save(){
		System.out.println("我是Save()方法");
	}
}

 

package junit.test;


import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.service.IPersonService;

public class SpringTest {
//	static ApplicationContext ctx=null;
	ItcastClassPathXMLApplicationContext ctx=new ItcastClassPathXMLApplicationContext("beans.xml");
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
//		ctx=new ClassPathXmlApplicationContext(new String[]{"bean.xml"});
//		System.out.println(ctx);
	}
	@Test
	public void test(){
		IPersonService personService = (IPersonService)ctx.getBean("personService");
		System.out.println(personService);
		personService.save();
	}
}

 

bean.xml

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" />
</beans>

 

注解类

package junit.test;

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

/** 元注解@Target,@Retention,@Documented,@Inherited 
* 
* @Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括: 
* ElemenetType.CONSTRUCTOR 构造器声明 
* ElemenetType.FIELD 域声明(包括 enum 实例) 
* ElemenetType.LOCAL_VARIABLE 局部变量声明 
* ElemenetType.METHOD 方法声明 
* ElemenetType.PACKAGE 包声明 
* ElemenetType.PARAMETER 参数声明 
* ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 
* 
* @Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括: 
* RetentionPolicy.SOURCE 注解将被编译器丢弃 
* RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 
* RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 
* 
* @Documented 将此注解包含在 javadoc 中 
* 
* @Inherited 允许子类继承父类中的注解



@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited */


@Retention(RetentionPolicy.RUNTIME)                     
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface ItcastResource {
	public String name() default "";                    //此注解有个name属性,类似@Resource(name="personDao")
}

 

 

注解处理器方法

private void annotationInject(){
		for(String beanName:singletons.keySet()){
			Object bean=singletons.get(beanName);
			if(bean!=null){
				try {
					PropertyDescriptor[] pds=Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
					for(PropertyDescriptor pd:pds){
						Method setter=pd.getWriteMethod();   //得到这个属性的setter方法
						if(setter!=null && setter.isAnnotationPresent(ItcastResource.class)){   //查看setter方法上没有ItcastResource注解
							ItcastResource resource=setter.getAnnotation(ItcastResource.class);  //取得这个注解
							Object value=null;
							if(resource.name()!=null && !"".equals(resource.name())){  //如果注解的名称属性不为空
								value=singletons.get(resource.name());  //取得这个bean实例
								setter.invoke(bean, value);
							}else{   //如果注解名称属性为空
								value=singletons.get(pd.getName());   //直接得到这个属性bean
								if(value==null){               //如果得不到这个属性的bean
									for(String key:singletons.keySet()){      //则遍历所有bean名称,找到类型相匹配的
										if(pd.getPropertyType().isAssignableFrom(singletons.get(key).getClass())){
											value=singletons.get(key);
											break;
										}
									}
								}
							}
							setter.setAccessible(true);
							setter.invoke(bean, value);   //把得到的依赖bean通过setter注入到bean
						}
					}
					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=singletons.get(resource.name());  //取得这个bean实例
							}else{   //如果注解名称属性为空
								value=singletons.get(field.getName());   //直接得到这个属性bean
								if(value==null){               //如果得不到这个属性的bean
									for(String key:singletons.keySet()){      //则遍历所有bean名称,找到类型相匹配的
										if(field.getType().isAssignableFrom(singletons.get(key).getClass())){
											value=singletons.get(key);
											break;
										}
									}
								}
							}
							field.setAccessible(true);  //允许访问私有字段
							field.set(bean, value);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	 

你可能感兴趣的:(spring容器)