作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
(以上摘选自:《百度百科》)
<dependencies>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
public class MyClassPathXmlApplicationContext implements ApplicationContext {
}
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;
private ConcurrentHashMap<String,Object> singletonMap;
private CopyOnWriteArrayList<BeanPostProcessor> beanPostProcessors;
private List<Element> elements;
String uri=this.getClass().getResource("/spring/"+configLocation).toURI().getPath();
String scp = uri.substring(1, uri.length());
SAXReader saxReader=new SAXReader();
Document document = saxReader.read(new File(scp));
Element rootElement = document.getRootElement();
if(!rootElement.getName().equals("my-beans")){
throw new NullPointerException("标签不正确");
}
ClassLoader classLoader = this.getClass().getClassLoader();
elements = rootElement.elements();
for (Element element : elements) {
if(!element.getName().equals("my-bean")){
throw new NullPointerException("标签不正确");
}
//beanName
String beanName=null;
//定义一个BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
List<Attribute> attributes = element.attributes();
for (Attribute attribute : attributes) {
if(attribute.getName().equals("id")){
beanName=attribute.getValue();
}else if(attribute.getName().equals("class")){
Class<?> aClass = classLoader.loadClass(attribute.getValue());
if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
BeanPostProcessor obj = (BeanPostProcessor) aClass.getConstructor().newInstance();
beanPostProcessors.add(obj);
}
beanDefinition.setType(aClass);
}else if(attribute.getName().equals("scope")){
beanDefinition.setScope(attribute.getValue());
}else {
throw new NullPointerException("属性不正确");
}
}
beanDefinitionMap.put(beanName,beanDefinition);
}
ConcurrentHashMap.KeySetView<String, BeanDefinition> keySet = beanDefinitionMap.keySet();
//加载入单例池
for (String beanName : keySet) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
String scope = beanDefinition.getScope();
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
//不做任何事
}else {
if(!singletonObjects.containsKey(beanName)){
Object obj = createBean(beanName);
singletonObjects.put(beanName,obj);
}
}
}
for (Element element : elements) {
String curBeanName = element.attributeValue("id");
xxx
}
List<Element> els = element.elements();
for (Element el : els) {
if(el.getName().equals("my-properties")){
if(el.element("my-ref")!=null){
String fieldName = el.attributeValue("name");
String bn = el.element("my-ref").attributeValue("bean");
Field field = aClass.getDeclaredField(fieldName);
field.setAccessible(true);
if(singletonObjects.containsKey(bn)){
Object beanObj = singletonObjects.get(bn);
field.set(obj,beanObj);
}
else{
Object createBean = createBean(bn);
field.set(obj,createBean);
}
}else{
List<Attribute> attributes = el.attributes();
//用于保存注入的字段
String field=null;
//用于保存注入的值
String val=null;
for (Attribute attribute : attributes) {
if(attribute.getName().equals("name")){
field=attribute.getValue();
}else if(attribute.getName().equals("value")){
val=attribute.getValue();
}else {
throw new NullPointerException("请检查定义bean的属性");
}
}
Field fd = aClass.getDeclaredField(field);
fd.setAccessible(true);
String type = fd.getType().getName().toLowerCase();
if(type.equals("byte")||type.equals("java.lang.byte")){
fd.set(obj,Byte.parseByte(val));
}else if(type.equals("short")||type.equals("java.lang.short")){
fd.set(obj,Short.parseShort(val));
}else if(type.equals("int")||type.equals("java.lang.integer")){
fd.set(obj,Integer.parseInt(val));
}else if(type.equals("long")||type.equals("java.lang.long")){
fd.set(obj,Long.parseLong(val));
}else if(type.equals("double")||type.equals("java.lang.double")){
fd.set(obj,Double.parseDouble(val));
}else if(type.equals("float")||type.equals("java.lang.float")){
fd.set(obj,Float.parseFloat(val));
}else if(type.equals("char")){
fd.set(obj,val.charAt(0));
}else if(type.equals("boolean")||type.equals("java.lang.boolean")){
if(val.equals("true")){
fd.set(obj,true);
}else{
fd.set(obj,false);
}
}else if(type.equals("java.lang.string")){
fd.set(obj,val);
}
else{
throw new NullPointerException("暂不支持这个字段类型");
}
}
}else {
throw new NullPointerException("请检查注入属性的标签");
}
}
package com.springframework.core.context;
import com.springframework.core.constant.ScopeType;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
/**
* 纯手写ClassPathXmlApplicationContext
* @author 游政杰
* TODO: 2022/3/22
*/
//说明MyClassPathXmlApplicationContext是ApplicationContext的实现类,可以通过多态的方式创建对象
public class MyClassPathXmlApplicationContext implements ApplicationContext {
//bean定义Map
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;
//单例池,也就是Spring的一级缓存
private ConcurrentHashMap<String,Object> singletonObjects;
//beanPostProcessors集合
private CopyOnWriteArrayList<BeanPostProcessor> beanPostProcessors;
//root结点下一个结点的集合
private List<Element> elements;
//私有化构造器
private MyClassPathXmlApplicationContext(){
}
public MyClassPathXmlApplicationContext(String configLocation){
this.beanDefinitionMap=new ConcurrentHashMap<>();
this.singletonObjects=new ConcurrentHashMap<>();
this.beanPostProcessors=new CopyOnWriteArrayList<>();
try {
//获取扫描xml文件,只扫描resources目录下的spring目录
String uri=this.getClass().getResource("/spring/"+configLocation).toURI().getPath();
String scp = uri.substring(1, uri.length());
//通过SAX阅读器去加载XML配置文件,并获取该XML配置文件的root结点也就是my-beans标签
//然后校验标签是否正确,如果标签不正确则抛出异常
//通过当前对象的类去拿到类加载器(ClassLoader)
//获取root结点的下一级结点的集合并且赋值给全局变量elements
//创建SAX阅读器
SAXReader saxReader=new SAXReader();
//加载XML文件
Document document = saxReader.read(new File(scp));
//获取root结点
Element rootElement = document.getRootElement();
//校验标签的正确性
if(!rootElement.getName().equals("my-beans")){
throw new NullPointerException("标签不正确");
}
//获取类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
//获取root结点的下一级结点的集合
elements = rootElement.elements();
//遍历root结点的下一级结点,这个结点就是我们定义的一个个bean
for (Element element : elements) {
//校验标签的正确性
if(!element.getName().equals("my-bean")){
throw new NullPointerException("标签不正确");
}
//beanName
String beanName=null;
//定义一个BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
//获取root结点的下一级结点的属性
List<Attribute> attributes = element.attributes();
//root结点的下一级结点的属性的值
for (Attribute attribute : attributes) {
//分别找出id、class、scope属性
if(attribute.getName().equals("id")){
beanName=attribute.getValue();
}else if(attribute.getName().equals("class")){
Class<?> aClass = classLoader.loadClass(attribute.getValue());
//判断这个类是否实现BeanPostProcessor
if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
BeanPostProcessor obj = (BeanPostProcessor) aClass.getConstructor().newInstance();
beanPostProcessors.add(obj);
}
beanDefinition.setType(aClass);
}else if(attribute.getName().equals("scope")){
beanDefinition.setScope(attribute.getValue());
}else {
throw new NullPointerException("属性不正确");
}
}
beanDefinitionMap.put(beanName,beanDefinition);
}
//扫描结束
ConcurrentHashMap.KeySetView<String, BeanDefinition> keySet = beanDefinitionMap.keySet();
//加载入单例池
for (String beanName : keySet) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
String scope = beanDefinition.getScope();
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
//不做任何事
}else {
if(!singletonObjects.containsKey(beanName)){
Object obj = createBean(beanName);
singletonObjects.put(beanName,obj);
}
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition==null){
return null;
}else {
String scope = beanDefinition.getScope();
//如果是多例
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
return createBean(beanName);
}else {//如果是单例的话先去单例池中找
Object obj = singletonObjects.get(beanName);
//如果单例池没有
if(obj==null){
obj=createBean(beanName);
}else {//单例池有的话直接返回obj
return obj;
}
}
}
return null;
}
private Object createBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition==null){
throw new NullPointerException("创建bean失败");
// return null;
}else {
try {
//依赖注入,二级标签,这既是一个个bean
for (Element element : elements) {
//遍历获取当前beanName
String curBeanName = element.attributeValue("id");
if(curBeanName.equals(beanName)){
Class<?> aClass = beanDefinition.getType();
//反射创建对象
Object obj = aClass.getConstructor().newInstance();
//注入的属性集,也就是第三级标签
List<Element> els = element.elements();
for (Element el : els) {
//只有这种情况才合法,因为我们目前只支持my-properties标签注入
if(el.getName().equals("my-properties")){
//判断这个标签的子标签是否是my-ref标签
if(el.element("my-ref")!=null){
String fieldName = el.attributeValue("name");
String bn = el.element("my-ref").attributeValue("bean");
Field field = aClass.getDeclaredField(fieldName);
field.setAccessible(true);
//通过bn去单例池里面找是否有
if(singletonObjects.containsKey(bn)){
//单例池如果有则用单例池的
Object beanObj = singletonObjects.get(bn);
field.set(obj,beanObj);
}
else{
//直接调用createBean方法创建对象并赋值
Object createBean = createBean(bn);
field.set(obj,createBean);
}
}else{
List<Attribute> attributes = el.attributes();
//用于保存注入的字段
String field=null;
//用于保存注入的值
String val=null;
for (Attribute attribute : attributes) {
if(attribute.getName().equals("name")){
field=attribute.getValue();
}else if(attribute.getName().equals("value")){
val=attribute.getValue();
}else {
throw new NullPointerException("请检查定义bean的属性");
}
}
//此时进行依赖注入,必须要是getDeclaredField方法
Field fd = aClass.getDeclaredField(field);
fd.setAccessible(true);
//为了防止注入报错,我们对注入的所有基本数据类型+String进行判断(变小写再判断)
String type = fd.getType().getName().toLowerCase();
if(type.equals("byte")||type.equals("java.lang.byte")){
fd.set(obj,Byte.parseByte(val));
}else if(type.equals("short")||type.equals("java.lang.short")){
fd.set(obj,Short.parseShort(val));
}else if(type.equals("int")||type.equals("java.lang.integer")){
fd.set(obj,Integer.parseInt(val));
}else if(type.equals("long")||type.equals("java.lang.long")){
fd.set(obj,Long.parseLong(val));
}else if(type.equals("double")||type.equals("java.lang.double")){
fd.set(obj,Double.parseDouble(val));
}else if(type.equals("float")||type.equals("java.lang.float")){
fd.set(obj,Float.parseFloat(val));
}else if(type.equals("char")){
fd.set(obj,val.charAt(0));
}else if(type.equals("boolean")||type.equals("java.lang.boolean")){
if(val.equals("true")){
fd.set(obj,true);
}else{
fd.set(obj,false);
}
}else if(type.equals("java.lang.string")){
fd.set(obj,val);
}
else{
throw new NullPointerException("暂不支持这个字段类型");
}
}
}else {
throw new NullPointerException("请检查注入属性的标签");
}
}
//依赖注入完成之后
//判断对象是否需要Aware回调
if(obj instanceof Aware){
//再具体判断是什么回调
if(obj instanceof BeanNameAware){
((BeanNameAware) obj).setBeanName(beanName);
}
}
//初始化前
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
beanPostProcessor.postProcessorBeforeInitialization(obj,beanName);
}
//初始化
if(obj instanceof InitializingBean){
((InitializingBean) obj).afterPropertiesSet();
}
//初始化后
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
beanPostProcessor.postProcessorAfterInitialization(obj,beanName);
}
//如果是单例就放入单例池
if(beanDefinition.getScope()==null||beanDefinition.getScope().equals(ScopeType.SINGLETON)){
singletonObjects.put(beanName,obj);
}
return obj;
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//如果找不到就会返回null
return null;
}
}
}
<my-beans>
<my-bean id="orderBean1" class="com.springframework.core.service.impl.OrderServiceImpl" >
<my-properties name="aByte" value="111"/>
<my-properties name="aShort" value="222"/>
<my-properties name="aInt" value="333"/>
<my-properties name="aLong" value="6666"/>
<my-properties name="aDouble" value="123.123"/>
<my-properties name="aFloat" value="233.567"/>
<my-properties name="aChar" value="c"/>
<my-properties name="aBoolean" value="true"/>
<my-properties name="aString" value="8大基本数据类型与String的注入测试"/>
my-bean>
<my-bean id="orderBean2" class="com.springframework.core.service.impl.OrderServiceImpl" scope="prototype">
<my-properties name="aByte" value="111"/>
<my-properties name="aShort" value="222"/>
<my-properties name="aInt" value="333"/>
<my-properties name="aLong" value="6666"/>
<my-properties name="aDouble" value="123.123"/>
<my-properties name="aFloat" value="233.567"/>
<my-properties name="aChar" value="c"/>
<my-properties name="aBoolean" value="true"/>
<my-properties name="aString" value="8大基本数据类型与String的注入测试---prototype"/>
my-bean>
<my-bean id="userBean1" class="com.springframework.core.service.impl.UserServiceImpl" scope="singleton">
<my-properties name="orderServiceImpl">
<my-ref bean="orderBean2"/>
my-properties>
my-bean>
<my-bean id="myBeanPostProcess" class="com.springframework.core.service.impl.MyBeanPostProcess" scope="singleton">
my-bean>
my-beans>
ApplicationContext applicationContext=new MyClassPathXmlApplicationContext("spring-service.xml");
OrderService orderBean1 = (OrderService) applicationContext.getBean("orderBean1");
System.out.println(orderBean1);
System.out.println(orderBean1.hashCode());
OrderService orderBean2 = (OrderService) applicationContext.getBean("orderBean2");
System.out.println(orderBean2);
System.out.println(orderBean2.hashCode());
UserService userBean1 = (UserService) applicationContext.getBean("userBean1");
System.out.println(userBean1);
// singleton
System.out.println(applicationContext.getBean("orderBean1").hashCode());
System.out.println(applicationContext.getBean("orderBean1").hashCode());
System.out.println(applicationContext.getBean("orderBean1").hashCode());
System.out.println("----多例---");
//prototype
System.out.println(applicationContext.getBean("orderBean2").hashCode());
System.out.println(applicationContext.getBean("orderBean2").hashCode());
System.out.println(applicationContext.getBean("orderBean2").hashCode());
输出结果
postProcessorBeforeInitialization
postProcessorAfterInitialization
postProcessorBeforeInitialization
postProcessorAfterInitialization
postProcessorBeforeInitialization
初始化Bean...
postProcessorAfterInitialization
postProcessorBeforeInitialization
初始化bean
postProcessorAfterInitialization
OrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试'}
1136497418
postProcessorBeforeInitialization
postProcessorAfterInitialization
OrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试---prototype'}
863125040
UserServiceImpl{orderServiceImpl=OrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试---prototype'}, beanName='userBean1'}
1136497418
1136497418
1136497418
----多例---
postProcessorBeforeInitialization
postProcessorAfterInitialization
949057310
postProcessorBeforeInitialization
postProcessorAfterInitialization
2024542466
postProcessorBeforeInitialization
postProcessorAfterInitialization
770189387