今天咱们就一起探索spring是怎么完成IOC/DI工作的,也自己做一个简单Spring框架!
Spring中Bean的定义
作用:在spring中使用的bean,都有某些公共属性,此类就是对公共属性的定义
- public class BeanDefine {
- public String id;
- public String className;
- public BeanDefine(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;
- }
- }
2,装配类
2.1,XML装配类
作用:对spring中Xml的配置进行类的装配,实际就是注入
- import java.beans.Introspector;
- import java.beans.PropertyDescriptor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.apache.log4j.Logger;
- import org.dom4j.Document;
- import org.dom4j.DocumentException;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import com.My.Test.TestServiceImpl;
- /**
- * @Description: spring中的注解原理
- * @ClassName: ClassPathXMLApplicationContext
- * @Project: MySpring
- * @Author: xvshu
- * @Date: 2015年2月28日
- */
- public class ClassPathXMLApplicationContext {
- Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);
- List<BeanDefine> beanList = new ArrayList<BeanDefine>();
- Map<String, Object> sigletions = new HashMap<String, Object>();
- public ClassPathXMLApplicationContext(String fileName) {
- //读取配置文件中管理的bean
- this.readXML(fileName);
- //实例化bean
- this.instancesBean();
- //注解处理器
- this.annotationInject();
- }
- /**
- * 读取Bean配置文件
- * @param fileName
- * @return
- */
- @SuppressWarnings("unchecked")
- public void readXML(String fileName) {
- Document document = null;
- SAXReader saxReader = new SAXReader();
- try {
- ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- document = saxReader.read(classLoader.getResourceAsStream(fileName));
- Element beans = document.getRootElement();
- for (Iterator<Element> beansList = beans.elementIterator(); beansList.hasNext();) {
- Element element = beansList.next();
- BeanDefine bean = new BeanDefine(
- element.attributeValue("id"),
- element.attributeValue("class"));
- beanList.add(bean);
- }
- } catch (DocumentException e) {
- log.info("读取配置文件出错....");
- }
- }
- /**
- * 实例化Bean
- */
- public void instancesBean() {
- for (BeanDefine bean : beanList) {
- try {
- sigletions.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());
- } catch (Exception e) {
- log.info("实例化Bean出错...");
- }
- }
- }
- /**
- * 注解处理器
- * 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,如果注解ZxfResource
- * 没有配置name属性,则根据属性所属类型来扫描配置文件获取要注入的实例引用
- *
- */
- public void annotationInject(){
- for(String beanName:sigletions.keySet()){
- Object bean = sigletions.get(beanName);
- if(bean!=null){
- this.propertyAnnotation(bean);
- this.fieldAnnotation(bean);
- }
- }
- }
- /**
- * 处理在set方法加入的注解
- * @param bean 处理的bean
- */
- public void propertyAnnotation(Object bean){
- try {
- //获取其属性的描述
- PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
- for(PropertyDescriptor proderdesc : ps){
- //获取所有set方法
- Method setter = proderdesc.getWriteMethod();
- //判断set方法是否定义了注解
- if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){
- //获取当前注解,并判断name属性是否为空
- ZxfResource resource = setter.getAnnotation(ZxfResource.class);
- String name ="";
- Object value = null;
- if(resource.name()!=null&&!"".equals(resource.name())){
- //获取注解的name属性的内容
- name = resource.name();
- value = sigletions.get(name);
- }else{ //如果当前注解没有指定name属性,则根据类型进行匹配
- for(String key : sigletions.keySet()){
- //判断当前属性所属的类型是否在配置文件中存在
- if(proderdesc.getPropertyType().isAssignableFrom(sigletions.get(key).getClass())){
- //获取类型匹配的实例对象
- value = sigletions.get(key);
- break;
- }
- }
- }
- //允许访问private方法
- setter.setAccessible(true);
- //把引用对象注入属性
- setter.invoke(bean, value);
- }
- }
- } catch (Exception e) {
- log.info("set方法注解解析异常..........");
- }
- }
- /**
- * 处理在字段上的注解
- * @param bean 处理的bean
- */
- public void fieldAnnotation(Object bean){
- try {
- //获取其全部的字段描述
- Field[] fields = bean.getClass().getDeclaredFields();
- for(Field f : fields){
- if(f!=null && f.isAnnotationPresent(ZxfResource.class)){
- ZxfResource resource = f.getAnnotation(ZxfResource.class);
- String name ="";
- Object value = null;
- if(resource.name()!=null&&!"".equals(resource.name())){
- name = resource.name();
- value = sigletions.get(name);
- }else{
- for(String key : sigletions.keySet()){
- //判断当前属性所属的类型是否在配置文件中存在
- if(f.getType().isAssignableFrom(sigletions.get(key).getClass())){
- //获取类型匹配的实例对象
- value = sigletions.get(key);
- break;
- }
- }
- }
- //允许访问private字段
- f.setAccessible(true);
- //把引用对象注入属性
- f.set(bean, value);
- }
- }
- } catch (Exception e) {
- log.info("字段注解解析异常..........");
- }
- }
- /**
- * 获取Map中的对应的bean实例
- * @param beanId
- * @return
- */
- public Object getBean(String beanId) {
- return sigletions.get(beanId);
- }
- }
- 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 ZxfResource {
- //注解的name属性
- public String name() default "";
- }
3,配置文件
3.1xml:
- <?xml version="1.0" encodi
- <beans>
- <bean id = "TestObject1" class="com.My.Test.TestObject1" />
- <bean id = "TestObject2" class="com.My.Test.TestObject2" />
- <bean id = "TestObject3" class="com.My.Test.TestObject3" />
- <bean id = "TestService" class = "com.My.Test.TestServiceImpl" />
- </beans>
3.2注解
- public class TestServiceImpl {
- public TestObject3 TestObject3;
- public TestObject1 TestObject1;
- // 字段上的注解,可以配置name属性
- @ZxfResource
- public TestObject2 TestObject2;
- // set方法上的注解,带有name属性
- @ZxfResource(name = "TestObject3")
- public void setUserDao(TestObject3 TestObject3) {
- this.TestObject3 = TestObject3;
- }
- // set方法上的注解,没有配置name属性
- @ZxfResource
- public void setUser1Dao(TestObject1 TestObject1) {
- this.TestObject1 = TestObject1;
- }
- public void show() {
- TestObject1.show1();
- TestObject2.show2();
- TestObject3.show();
- System.out.println("调用了TestService方法........");
- }
- }
4,测试类
和普通spring类一样的写法
- public static void main(String[] args) {
- ClassPathXMLApplicationContext path = new ClassPathXMLApplicationContext(
- "configAnnotation.xml");
- TestServiceImpl userService =(TestServiceImpl)path.getBean("TestService");
- userService.show();
- }