作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/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的架构进行梳理,实现了其扫描包组件、及控制反转(IOC)容器、以及Component、ComponentScan、Scope等注解功能,(DI和AOP)等功能将在后面进行逐步完善。如有不足,请谅解。
我们手写的Spring起名叫:MySpringFramework
项目包结构介绍
com.springframework.core:这个包是我们的核心包,所有核心文件都放在这
com.springframework.core.annotation:注解包
com.springframework.core.config:启动配置包,例如MyComponentScan注解配置类
com.springframework.core.constant:常量包
com.springframework.core.context:Spring的核心内容包,例如MyAnnotationConfigApplicationContext上下文。
com.springframework.core.exception:自定义异常类的包
com.springframework.core.service:用户写的类都放在这里等待被扫描。
com.springframework.test:测试Spring功能包
package com.springframework.core.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface MyAutowired {
}
package com.springframework.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyComponent {
String value() default ""; //组件beanName
}
package com.springframework.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyComponentScan {
String value();
}
package com.springframework.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyScope {
String value();
}
作用是指定@MyComponent作用的类上是单例还是多例。
如果不指定,默认是单例singleton。
package com.springframework.core.constant;
import java.io.Serializable;
/**
* scope的类型常量
* 例如:单例和多例
*/
public final class ScopeType implements Serializable {
private ScopeType(){}
//单例
public static final String SINGLETON="singleton";
//多例
public static final String PROTOTYPE="prototype";
}
package com.springframework.core.config;
import com.springframework.core.annotation.MyComponentScan;
/**
* Spring的配置类
*/
@MyComponentScan("com.springframework.core.service")//扫描包名
public class SpringApplicationConfig {
}
package com.springframework.core.context;
import java.io.Serializable;
/**
* bean的定义
* @author 游政杰
* TODO: 2022/3/20
*/
public class BeanDefinition implements Serializable {
private Class<?> type; //bean所属类
private String scope; //单例还是多例
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString() {
return "BeanDefinition{" +
"type=" + type +
", scope='" + scope + '\'' +
'}';
}
}
package com.springframework.core.service;
public interface UserService {
}
package com.springframework.core.service;
import com.springframework.core.annotation.MyComponent;
import com.springframework.core.annotation.MyScope;
import com.springframework.core.constant.ScopeType;
import com.springframework.core.service.UserService;
@MyComponent //标记组件
@MyScope(ScopeType.SINGLETON) //标记单例
public class UserServiceImpl implements UserService {
}
package com.springframework.core.context;
/**
* 手写Spring框架
* @author 游政杰
*/
public interface ApplicationContext {
Object getBean(String beanName);
}
package com.springframework.core.context;
import com.springframework.core.annotation.MyComponent;
import com.springframework.core.annotation.MyComponentScan;
import com.springframework.core.annotation.MyScope;
import com.springframework.core.constant.ScopeType;
import com.springframework.core.exception.NotSuchBeanException;
import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* 纯手写一个Spring框架
* @author 游政杰
* TODO: 2022/3/19
*/
public class MyAnnotationConfigApplicationContext implements ApplicationContext {
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;
private ConcurrentHashMap<String,Object> singletonMap;
private MyAnnotationConfigApplicationContext(){}
public MyAnnotationConfigApplicationContext(final Class<?> configClass) {
try {
if (configClass.isAnnotationPresent(MyComponentScan.class)) {
this.beanDefinitionMap=new ConcurrentHashMap<>();
this.singletonMap=new ConcurrentHashMap<>();
MyComponentScan componentScan = configClass.getAnnotation(MyComponentScan.class);
String scc = componentScan.value();
String sc = scc.replace(".", "/");
ClassLoader classLoader = this.getClass().getClassLoader();
String uri = Objects.requireNonNull(classLoader.getResource(sc)).toURI().getPath();
String scp = uri.substring(1, uri.length());
File dir = new File(scp);
if (dir.isDirectory()) {
File[] files = dir.listFiles();
if(files!=null&&files.length>0){
for (File file : files) {
//暂时不做这个处理。这个可以递归实现
// if(file.isDirectory()){
//
// }
if(file.getName().endsWith(".class")){
//取类名
String cn = file.getName().substring(0,file.getName().length()-6);
//全类名
String className=scc+"."+cn;
Class<?> aClass = classLoader.loadClass(className);
if(!aClass.isInterface()&&aClass.isAnnotationPresent(MyComponent.class)) {
BeanDefinition beanDefinition = new BeanDefinition();
//获取类名
String simpleName = aClass.getSimpleName();
String beanName = Introspector.decapitalize(simpleName);
beanDefinition.setType(aClass);
if(aClass.isAnnotationPresent(MyScope.class)){
MyScope myScope = aClass.getAnnotation(MyScope.class);
String sv = myScope.value();
//为null则报错
sv = Objects.requireNonNull(sv);
if(sv.equals(ScopeType.PROTOTYPE)){
beanDefinition.setScope(ScopeType.PROTOTYPE);
}else {
beanDefinition.setScope(ScopeType.SINGLETON);
}
}
beanDefinitionMap.put(beanName,beanDefinition);
}
}
}
}
}
ConcurrentHashMap.KeySetView<String, BeanDefinition>
beanDefinitionKeySetView = beanDefinitionMap.keySet();
for (String beanName : beanDefinitionKeySetView) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
String scope = beanDefinition.getScope();
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
}else {
if(!singletonMap.containsKey(beanName)){
Object obj = this.createBean(beanName);
singletonMap.put(beanName,obj);
}
}
}
}else {
throw new RuntimeException("指定配置类上没有MyComponentScan注解存在");
}
}catch (URISyntaxException e1){
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private Object createBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition==null){
throw new NotSuchBeanException("beanDefinitionMap没有该bean的定义");
}else {
Class<?> aClass = beanDefinition.getType();
try {
Object obj = aClass.getConstructor().newInstance();
return obj;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
}
@Override
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition==null){
// throw new NotSuchBeanException("beanDefinitionMap没有该bean的定义");
return null;
}else {
String scope = beanDefinition.getScope();
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
Object obj = this.createBean(beanName);
return obj;
}else {
if(singletonMap.containsKey(beanName)){
return singletonMap.get(beanName);
}else {
Object obj = this.createBean(beanName);
singletonMap.put(beanName,obj);
return obj;
}
}
}
}
}
1:容器变量定义
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;
private ConcurrentHashMap<String,Object> singletonMap;
beanDefinitionMap在初始化阶段就会把单例和多例的类封装成BeanDefinition对象放入,Map的格式为
singletonMap单例池,singletonMap和beanDefinitionMap的区别就是singletonMap存放的全都是单例,并且value全都是经过beanDefinitionMap的值通过反射生成的。该Map的格式为
2:
if (configClass.isAnnotationPresent(MyComponentScan.class)) {
xxx
}
3:
MyComponentScan componentScan = configClass.getAnnotation(MyComponentScan.class);
String scc = componentScan.value();
4:
String sc = scc.replace(".", "/");
5:
ClassLoader classLoader = this.getClass().getClassLoader();
//这种写法可以防止Java把空格路径转换成%20而导致找不到文件夹
String uri = Objects.requireNonNull(classLoader.getResource(sc)).toURI().getPath();
String scp = uri.substring(1, uri.length());
File dir = new File(scp);
6:
if(file.getName().endsWith(".class")){
}
7:
//取类名
String cn = file.getName().substring(0,file.getName().length()-6);
//全类名
String className=scc+"."+cn;
Class<?> aClass = classLoader.loadClass(className);
8:
if(!aClass.isInterface()&&aClass.isAnnotationPresent(MyComponent.class)) {
}
9:
BeanDefinition beanDefinition = new BeanDefinition();
//获取类名
String simpleName = aClass.getSimpleName();
String beanName = Introspector.decapitalize(simpleName);
//beanDefinition的class类型
beanDefinition.setType(aClass);
10:
if(aClass.isAnnotationPresent(MyScope.class)){
}
beanDefinitionMap.put(beanName,beanDefinition);
11:
ConcurrentHashMap.KeySetView<String, BeanDefinition>
beanDefinitionKeySetView = beanDefinitionMap.keySet();
//遍历出beanName
for (String beanName : beanDefinitionKeySetView) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
String scope = beanDefinition.getScope();
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){ //多例则不管它
//不做任何事
}else {
//如果是单例的,我们就要去单例池找一下,看看有没有
if(!singletonMap.containsKey(beanName)){//如果单例池没有这个对象就要创建了
//创建对象
Object obj = this.createBean(beanName);
//放入单例池
singletonMap.put(beanName,obj);
}
}
}
11:createBean
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition==null){
throw new NotSuchBeanException("beanDefinitionMap没有该bean的定义");
}else {
Class<?> aClass = beanDefinition.getType();
try {
Object obj = aClass.getConstructor().newInstance();
return obj;
}
12:getBean
//判断是单例还是多例
String scope = beanDefinition.getScope();
//如果是单例的话
if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){
//多例则每次都创建对象
Object obj = this.createBean(beanName);
return obj;
}else {
//如果是单例的,我们就要去单例池找一下,看看有没有
//如果有的话就返回这个单例池对象即可
if(singletonMap.containsKey(beanName)){
//返回bean对象
return singletonMap.get(beanName);
}else { //如果单例池没有这个对象就要创建了
//创建对象
Object obj = this.createBean(beanName);
//放入单例池
singletonMap.put(beanName,obj);
return obj;
}
}
package com.springframework.test;
import com.springframework.core.config.SpringApplicationConfig;
import com.springframework.core.context.ApplicationContext;
import com.springframework.core.context.MyAnnotationConfigApplicationContext;
import java.beans.Introspector;
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext=new MyAnnotationConfigApplicationContext(SpringApplicationConfig.class);
System.out.println(applicationContext.getBean("userServiceImpl"));
System.out.println(applicationContext.getBean("userServiceImpl"));
System.out.println(applicationContext.getBean("userServiceImpl"));
System.out.println(applicationContext.getBean("userServiceImpl"));
System.out.println(applicationContext.getBean("userServiceImpl"));
}
}
com.springframework.core.service.UserServiceImpl@51565ec2
com.springframework.core.service.UserServiceImpl@51565ec2
com.springframework.core.service.UserServiceImpl@51565ec2
com.springframework.core.service.UserServiceImpl@51565ec2
com.springframework.core.service.UserServiceImpl@51565ec2