这篇博客主要是记录一下如何简单的实现一个Spring容器
1.首先一个maven项目结构如下 主要有两个包spring这个包就是实现spring容器的代码
2.这里展示的是Test类的代码,我们通过自己定义的BaoboApplicationContext 类根据配置类AppConfig得到我们
UserService 对象
public class Test {
public static void main(String[] args) throws Exception {
//BaoboApplicationContext 这个我们自己创建的容器类似于spring的
BaoboApplicationContext baoboApplicationContext = new BaoboApplicationContext(AppConfig.class);
UserService UserService = (UserService) baoboApplicationContext.getBean("UserService");
UserService.test();
}
}
3.AppConfig使我们自定的类,上面有我们自定的注解ComponentScan标志我们扫描的类的目录
@ComponentScan("com.baobo.service")
public class AppConfig {
}
4.自定义ComponentScan注解,用来告诉spring要扫描的包的路径
@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.TYPE)//类上
public @interface ComponentScan {
String value() default "";
}
5.自定义Component注解,用来告诉spring这个注解标注的类交给spring管理
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
6.自定义Scope注解,告诉spring这类是原型还单例
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "singleton";
}
7.接下来这个类BaoboApplicationContext 就是我们实现spring容器的重点,下面是这个类的结构:
首先是这个类的构造方法,构造方法通过传入的配置类AppConfig,然后调用scan方法来解析的这个类,可以参照下面的代码,主要的解析过程:
1、通过反射拿到配置类上的注解;
2、通过注解拿到注解的值也就是我们要扫描的包的路径;
3、通过类加载器来加载路径的类
4、加载完类后通过Cpmpomemt注解来确定哪些类是交给spring容器管理的
5. 通过Scope来判断哪些类是单例,哪些类是原型
在这个类里面还有几个比较重要的集合:
//单例池,用来存放创建好的容器对象
private ConcurrentHashMap<String, Object> single = new ConcurrentHashMap<>();
//bean定义集合,用来存放交给spring管理的哪些对象的信息
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionConcurrentHashMap = new ConcurrentHashMap<>();
//spring提供的类增强工具
private ArrayList<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
解析完配置类,接下来就是创建Bean的过程主要调用的是createBean方法,同样可参照下面的代码,主要的创建过程:
1、通过bean的定义信息得到一个对象,接下来就是依赖注入,判断这个类的属性有没有Autowired注解,如果有根据属性的名字创建bean,然后将这个bean注入到对象中
2、判断这个对象是否实现BeanNameAware这个接口 aware回调,这个spring提供的回调方法
3、同理判断这个对象是否实现BeanPostProcessor,InitializingBean这些接口,它们都是spring在创建对象的过程中,提供给程序员可以对对象进行增强的方法
创建完容器之后,我们就可以通过getBean方法得到我们要的对象
这是一个简单的spring的容器的实现过程
package com.spring;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class BaoboApplicationContext {
private Class configClass;
//单例池
private ConcurrentHashMap<String, Object> single = new ConcurrentHashMap<>();
//bean定义集合
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionConcurrentHashMap = new ConcurrentHashMap<>();
private ArrayList<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
public BaoboApplicationContext( Class configClass) throws Exception {
this.configClass=configClass;
//调用scan解析配置类,主要是解析配置类上的注解
scan(configClass);
//通过bean定义信息来创建帝乡 如果是单例先给它创建好
Set<Map.Entry<String, BeanDefinition>> entries = beanDefinitionConcurrentHashMap.entrySet();
for (Map.Entry<String, BeanDefinition> entry : entries) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")){
Object bean = createBean(beanName,beanDefinition);
single.put(beanName,bean);
}
}
}
public Object createBean(String beanName,BeanDefinition beanDefinition) throws Exception {
Class clazz = beanDefinition.getClazz();
Object instance = clazz.getDeclaredConstructor().newInstance();
//依赖注入
Field[] declaredField = clazz.getDeclaredFields();
for (Field field : declaredField) {
//如果有自动注入的
if (field.isAnnotationPresent(Autowired.class)){
//得到属性的名字,根据名字创建bean,将bean注入
String name = field.getName();
Object bean = getBean(name);
//
field.setAccessible(true);
field.set(instance,bean);
}
}
//这个对象是否实现BeanNameAware这个接口 aware回调
if (instance instanceof BeanNameAware){
((BeanNameAware) instance).setBeanName(beanName);
}
//初始化前
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
}
//初始化
if (instance instanceof InitializingBean){
((InitializingBean) instance).afterPropertiesSet();
}
//初始化后
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
}
//BeanPostProcessor
return instance;
}
private void scan(Class configClass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//得到扫描的路径
String path = componentScan.value();
System.out.println(path);
//扫描
//得到app类加载器
ClassLoader classLoader = BaoboApplicationContext.class.getClassLoader();
//通过注解进行扫描,得到该路径
String path1 = path.replace(".", "//");
URL resource = classLoader.getResource(path1);
System.out.println(resource);
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File file1 : files) {
String file1Name = file1.getAbsolutePath();
//返回一个字符串,该字符串是该字符串的子字符串。 *子字符串以指定索引处的字符开头,并且*扩展到该字符串的末尾
String className = file1Name.substring(file1Name.indexOf("com"),file1Name.indexOf(".class"));
String replace = className.replace("\\", ".");
System.out.println(replace);
//根据路径,用类加载器加载类
Class<?> aClass = classLoader.loadClass(replace);
//如果这个类存在component注解,表示这个一个bean
if (aClass.isAnnotationPresent(Component.class)) {
//判断这个类是不是实现BeanPostProcessor
if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
BeanPostProcessor instance = (BeanPostProcessor) aClass.getConstructor().newInstance();
beanPostProcessors.add(instance);
}
//判断这个类是单例还是原型
//BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
Component declaredAnnotation = aClass.getDeclaredAnnotation(Component.class);
beanDefinition.setClazz(aClass);
//拿到Component注解的值
String beanName = declaredAnnotation.value();
if (aClass.isAnnotationPresent(Scope.class)){
Scope declaredAnnotation1 = aClass.getDeclaredAnnotation(Scope.class);
String value2 = declaredAnnotation1.value();
beanDefinition.setScope(value2);
}else {
//默认是单例bbean
beanDefinition.setScope("singleton");
}
beanDefinitionConcurrentHashMap.put(beanName,beanDefinition);
}
}
}
}
public Object getBean(String beanName) throws Exception {
//判断这个bean是不是在容器里面
if (beanDefinitionConcurrentHashMap.containsKey(beanName)){
//判断是不是单例bean
BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
if (single.containsKey(beanName)) {
Object o = single.get(beanName);
return o;
}else {
//不是单例,就新建一个bean
Object bean = createBean(beanName,beanDefinition);
return bean;
}
}else {
//没有这个bean
throw new NullPointerException();
}
}
}