zoukankan      html  css  js  c++  java
  • Spring IOC

    众所周知,Spring向来以IOC和AOP独创江湖,这是Spring的招牌和成名作。一直以来只是学着用Spring去快速开发一些项目,只知道如何配置实用,却没有去仔细看一下Spring的IOC是个什么东东。于是在网上找到几个介绍Spring IOC的文章,看过之后发现IOC的概念也没有什么难理解的,不过,Spring将其发光发热了,将IOC用的炉火纯青,淋漓尽致。好了,我就把一些介绍IOC的文章粗略记录一下吧,以备复习之用,参考了很多别人的文章,在此一并谢过!

    IOC(有人也叫DI),就是控制反转,也叫依赖注入。大体的意思就是:不再靠程序员去手动创建类,由Spring替你创建和管理,降低业务逻辑之间的耦合程度。那么简答一句话:控制反转,到底控制什么反转了?答案就是获取对象的方式。我们可以简单地把IOC理解为一个管家,作为主人的你,你需要告诉你需要什么样的东西,管家就会帮你找出来,前提当然是这个东西是你的并且管家也知道有这么个东西。哈哈哈,有管家真好。。。

    那么,Spring是如何实现IOC的呢?最好的方式是去看源代码,不过如果你只是想了解IOC,那么下面的例子可能会对你有帮助。

    如何实现IOC,大体思路如下:

    1.实现接口或者继承超类

    2.使用setter方式或者构造函数的方式定义注入类

    3.调用IOC获得注入类并调用其实现方法

    假设场景:项目经理要你开发一个获取数据库时间的通用模块,要你兼容Mysql,Oracle,SQLServer,客户端调用者只需要传入要调用哪种数据库,你就返回对应的数据库时间。你会怎么做?

    1.声明一个获取数据库时间的接口,提供一个获取数据库时间的接口方法

    package com.robin;
    
    
    public interface IDataBase {
    	
    	public String getDate();
    
    }

    2.声明三个实现接口的类

    package com.robin;
    
    
    public class MySqlImpl implements IDataBase {
    
    	@Override
    	public String getDate() {
    		return "MYSQL的时间是2010-mysql";
    	}
    
    }
    
    package com.robin;
    
    
    public class OracleImpl implements IDataBase {
    
    	@Override
    	public String getDate() {
    		return "Oracle的时间是2010-oracle";
    	}
    
    }
    
    package com.robin;
    
    
    public class SqlServerImpl implements IDataBase {
    
    	@Override
    	public String getDate() {
    		return "SqlServer的时间是2010-SqlServer";
    	}
    
    }
    
    3.使用setter方式或者构造函数的方式定义注入类
    package com.robin;
    
    public class BaseDataImpl {
    	
    	private IDataBase database;
    	
    	public void setDatebase(IDataBase database){
    		this.database = database;
    	}
    	
    	public BaseDataImpl(IDataBase database){
    		this.database = database;
    	}
    	
    	public String getDate(){
    		return database.getDate();
    	}
    
    }
    

    4.测试一下

    package com.robin;
    
    public class TestGetDate {
    	
    	public static void main(String[] args) {
    		BaseDataImpl base = new BaseDataImpl(new MySqlImpl());
    		BaseDataImpl base1 = new BaseDataImpl(new OracleImpl());
    		BaseDataImpl base2 = new BaseDataImpl(new SqlServerImpl());
    		
    		System.out.println(base.getDate());
    		System.out.println(base1.getDate());
    		System.out.println(base2.getDate());
    	}
    
    }

    在测试类中调用不懂得实现类,就会输入不同的时间,我们就实现了不再采用new的方式去获取对象,只需要传入一个标示数据库类型的名字就可以了,这就是IOC的简单实现,Spring的IOC原理大体也是这样的。

    下面让我们一起来了解一下Spring是如何运行的

    public static void main(String[] args) {
    	ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
    	Animal animal = (Animal) context.getBean("animal");
    	animal.say();
    }

    那么我们先看一下applicationContext.xml中是怎么配置的

    <bean id="animal" class="phz.springframework.test.Cat">
    	<property name="name" value="kitty" />
    </bean>
    

    这个配置文件声明了一个Cat类,并且该类有一个成员属性:name

    public class Cat implements Animal {
    	private String name;
    	public void say() {
    		System.out.println("I am " + name + "!");
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

    该类还实现了一个Animal的接口

    public interface Animal {
    	public void say();
    }
    

    很明显该测试的输出结果是:I am kitty

    那么Spring是如何进行查找和执行的呢?

    首先,我们先创建一个Bean,用来存放一个Bean拥有的属性

    /* Bean Id */
    private String id;
    /* Bean Class */
    private String type;
    /* Bean Property */
    private Map<String, Object> properties = new HashMap<String, Object>();
    

    一个Bean包括id,type和properties。接下来Spring就开始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,这个HashMap中的key就是bean的Id,HashMap的value就是这个bean。这样我们就能通过context.getBean("animal");来获取Animal这个类。Spring不但可以注入基本类型,还可以注入像List,Map这样的类型。

    <bean id="test" class="Test">
    		<property name="testMap">
    			<map>
    				<entry key="a">
    					<value>1</value>
    				</entry>
    				<entry key="b">
    					<value>2</value>
    				</entry>
    			</map>
    		</property>
    	</bean>
    

    Spring是如何保存的呢?

    if (beanProperty.element("map") != null) {
    					Map<String, Object> propertiesMap = new HashMap<String, Object>();
    					Element propertiesListMap = (Element) beanProperty
    							.elements().get(0);
    					Iterator<?> propertiesIterator = propertiesListMap
    							.elements().iterator();
    					while (propertiesIterator.hasNext()) {
    						Element vet = (Element) propertiesIterator.next();
    						if (vet.getName().equals("entry")) {
    							String key = vet.attributeValue("key");
    							Iterator<?> valuesIterator = vet.elements()
    									.iterator();
    							while (valuesIterator.hasNext()) {
    								Element value = (Element) valuesIterator.next();
    								if (value.getName().equals("value")) {
    									propertiesMap.put(key, value.getText());
    								}
    								if (value.getName().equals("ref")) {
    									propertiesMap.put(key, new String[] { value
    											.attributeValue("bean") });
    								}
    							}
    						}
    					}
    					bean.getProperties().put(name, propertiesMap);
    				}
    

    然后就是最核心的部分了,让我们看一下Spring是如何实现依赖注入的吧,其实也非常简单,就是通过反射机制。在实例化一个类时,先通过反射调用类中的set方法将保存在HashMap中的类属性注入到类中。

    首先是先实例化一个类:使用的反射

    public static Object newInstance(String className) {
    		Class<?> cls = null;
    		Object obj = null;
    		try {
    			cls = Class.forName(className);
    			obj = cls.newInstance();
    		} catch (ClassNotFoundException e) {
    			throw new RuntimeException(e);
    		} catch (InstantiationException e) {
    			throw new RuntimeException(e);
    		} catch (IllegalAccessException e) {
    			throw new RuntimeException(e);
    		}
    		return obj;
    	}
    然后将这个类的属性及方法注入进去
    public static void setProperty(Object obj, String name, String value) {
    		Class<? extends Object> clazz = obj.getClass();
    		try {
    			String methodName = returnSetMthodName(name);
    			Method[] ms = clazz.getMethods();
    			for (Method m : ms) {
    				if (m.getName().equals(methodName)) {
    					if (m.getParameterTypes().length == 1) {
    						Class<?> clazzParameterType = m.getParameterTypes()[0];
    						setFieldValue(clazzParameterType.getName(), value, m,
    								obj);
    						break;
    					}
    				}
    			}
    		} catch (SecurityException e) {
    			throw new RuntimeException(e);
    		} catch (IllegalArgumentException e) {
    			throw new RuntimeException(e);
    		} catch (IllegalAccessException e) {
    			throw new RuntimeException(e);
    		} catch (InvocationTargetException e) {
    			throw new RuntimeException(e);
    		}
    }
    

    最后Spring将实例返回给我们

    if (value instanceof Map) {
    				Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()
    						.iterator();
    				Map<String, Object> map = new HashMap<String, Object>();
    				while (entryIterator.hasNext()) {
    					Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();
    					if (entryMap.getValue() instanceof String[]) {
    						map.put((String) entryMap.getKey(),
    								getBean(((String[]) entryMap.getValue())[0]));
    					}
    				}
    				BeanProcesser.setProperty(obj, property, map);
    			}
    

    这里只是举个例子,实际Spring做的工作远不止这些,我们理解Spring的工作原理就好了。

  • 相关阅读:
    powerdesigner得使用放法
    sql sever连接名忘记了该怎么办
    算法第四版 1.2.10
    算法第四版 1.2.8
    算法第四版 1.2.6
    算法第四版 1.2.2
    二分查找递归实现
    关于斐波那契数列和递归
    编写一段代码,打印一个M行N列的二维数组转置。(交换行和列)
    基础实验2-2.1 整数的分类处理 (20分)
  • 原文地址:https://www.cnblogs.com/luckyliu/p/2461603.html
Copyright © 2011-2022 走看看