这些天刚学习了一点spring框架的一点东西,看了很多大神的理解和看法,关于spring框架 其中有几大模块但是总的来说分为两种思想,意识oop思想也就是java语言的核心思想面向对象编程,但是spring还有一种就是aop也就是面向方面编程,这也是spring框架比较的优点吧。
这里我们不讨论这个,先来说说入门的ioc 以及ClassPathXMLApplicationContext 的简单重写吧
IOC(inversion of control)控制反转
概念:控制权由对象本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系。
核心:spring封装了抽象工厂模式;bean工厂创建的各个实例称作为bean。
理解:喜欢吃的东西不一定自己亲自去做,交给食品加工厂去做不是更好吗。spring让一个对象不用创建new了,可以自动生产,这就是利用Java的反射机制动态创建、调用对象,spring就是在运行时,根xml 是pring配置文件动态创建对象,和调用对象里的方法的。
spring IOC 应用了单例模式,一次new一个全局对象,也可以在配置文件中进行配置,配置为不使用单例模式。
切面编程:Spring提供了切面编程的丰富支持,允许分离应用的业务逻辑与服务。
容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建—一个可配置的原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例,以及它们是如何关联的。
框架:Spring可以将简单的组件配置,组成为复杂的应用,在Spring中应用对象被声明式组合,典型地是在一个XML文件里,Spring提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了我们。
一下是重写的核心代码,首先我们需要导入spring-context的架包,一下是maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.8.RELEASE</version>
</dependency> -->
我这一导入的是4.3.8版本的目前spring框架已经更新5.0以后的版本的各位可以根据自己的需要导入自己的版本
下面是关于对象元素的获取和注入的一些代码,主要需要用到的工具是java的反射来实现的
//这里我们实现写了个ApplicationContext然后实现它
public class ClassPathXMLApplicationContext implements ApplicationContext {
//通过键值对来获取标识符,和对象
private Map<String,Object> container = new HashMap<>();
public Map<String, Object> getContainer() {
return container;
}
public void setContainer(Map<String, Object> container) {
this.container = container;
}
@Override
public Object getBean(String id) {
return container.get(id);
}
//1.使用jdom读取xml文件
//2.获取xml标签
//3.使用反射创建对象,并且初始化,然后存入容器中去
public ClassPathXMLApplicationContext(String path){
SAXBuilder builder = new SAXBuilder();
Document document = null;
try {
//读取xml文件
document = builder.build(ClassPathXMLApplicationContext.class.getClassLoader().getResourceAsStream(path));
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//获取首标签并便利标签内的元素获取bean的id及class的值
Element root = document.getRootElement();
List<Element> children = root.getChildren("bean");
for(Element child : children){
//获取id和class的value
String key = child.getAttributeValue("id");
String classStr = child.getAttributeValue("class");
try {
//创建对象并存入session中这里定义的是container
Object value = Class.forName(classStr).newInstance();
container.put(key, value);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
try{
//通过循环多去对象中存储的属性以及的值然后注入
for(Element child : children){
Object obj = container.get(child.getAttributeValue("id"));
List<Element> properties = child.getChildren("property");
//先判断处理的元素是否是ref标签,如果是那么说明元素包含的是一个子对象那
//么需要再次处理读取子对象的属性
for(Element property : properties){
String ref = property.getAttributeValue("ref");
String setStr = "";
Object value = null;
Method setter = null;
if(ref != null){
setStr = "set".concat(ref.substring(0,1).toUpperCase()).concat(ref.substring(1));
value = container.get(ref);
setter = obj.getClass().getMethod(setStr, value.getClass().getInterfaces()[0]);
}else{
//如果不是对象直接通过反射获取属性及值注入对象中
String name = property.getAttributeValue("name");
setStr = "set".concat(name.substring(0,1).toUpperCase()).concat(name.substring(1));
Field field = obj.getClass().getDeclaredField(name);
String stringValue = property.getAttributeValue("value");
setter = obj.getClass().getDeclaredMethod(setStr, field.getType());
System.out.println("type : " + field.getType().getName());
if(field.getType().getName().endsWith("Integer")) {
Integer v = Integer.parseInt(stringValue);
setter.invoke(obj, v);
}else if(field.getGenericType().getTypeName().endsWith("String")) {
setter.invoke(obj, stringValue);
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
以一下是ApplicationContext接口的写法
public interface ApplicationContext {
Object getBean(String id);
}
好了以上就这些了希望这个简单demo能帮助那些不能理解ClassPathXMLApplicationContext 原理的人一点帮助。