只是简单的按照Spring的执行流程写了一下代码,当然跟Spring源码是有很大的差别,可以拿来学习,不喜勿碰。支持单例和原型的bean,以及初始化前、初始化、初始化后的方法执行,可以解析各种定义的注解
执行流程
工程机构
关键代码,代码路径:xqc-structure: 模拟手写spring
package com.xqc.context;
import com.xqc.annotation.*;
import com.xqc.aware.XqcBeanAware;
import com.xqc.aware.XqcBeanPostProcessor;
import com.xqc.aware.XqcInitializingBean;
import com.xqc.definition.XqcBeanDefinition;
import com.xqc.enums.ScopeEnum;
import com.xqc.exception.ThrowUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
public class XqcApplicationContext {
//bean定义
private static final Map<String, XqcBeanDefinition> beanDefinitions = new HashMap<>();
//单例bean池
private static final Map<String,Object> singletonObjects = new HashMap<>();
//bean后置处理器
private static final List<XqcBeanPostProcessor> beanPostProcessors = new LinkedList<>();
public XqcApplicationContext(Class<?> clazz){
if (!clazz.isAnnotationPresent(XqcConfiguration.class)) {
ThrowUtils.throwEx("扫描配置不正确");
}
//1、解析入口配置类,生成扫描路径
String packagePath = getPackagePath(clazz);
//2、扫描包,生成beanDefinitions
scan(packagePath);
//3、解析和生成bean
this.refresh();
}
private void refresh(){
for (Map.Entry<String, XqcBeanDefinition> entry : beanDefinitions.entrySet()) {
String beanName = entry.getKey();
XqcBeanDefinition xqcBeanDefinition = entry.getValue();
if (ScopeEnum.PROTOTYPE.getCode().equals(xqcBeanDefinition.getScope())) {
continue;
}
//实例化,生成bean对象
Object bean = createBean(beanName, xqcBeanDefinition);
//放入map
singletonObjects.put(beanName,bean);
}
}
/**
* 生成beanDefinitions
* @param packagePath
*/
private void scan(String packagePath) {
//2、根据路径扫描文件,获取class
List<String> classes = new ArrayList<>();
scannerPackage(classes,packagePath);
for (String class1 : classes) {
try {
//加载成class方便后续判断
Class<?> aClass = XqcApplicationContext.class.getClassLoader().loadClass(subPath(class1));
//是否有XqcComponent注解
if(!aClass.isAnnotationPresent(XqcComponent.class)){
continue;
}
//是否实现XqcBeanPostProcessor接口
if(XqcBeanPostProcessor.class.isAssignableFrom(aClass)){
Object instance = aClass.getConstructor().newInstance();
beanPostProcessors.add((XqcBeanPostProcessor) instance);
}
XqcBeanDefinition beanDefinition = new XqcBeanDefinition();
//获取bean名称
String beanName = getBeanName(aClass);
beanDefinition.setClazz(aClass);
beanDefinition.setBeanName(beanName);
//解析XqcScope注解
if(aClass.isAnnotationPresent(XqcScope.class)){
XqcScope xqcScopeAnnotation = aClass.getAnnotation(XqcScope.class);
if(!ScopeEnum.PROTOTYPE.getCode().equals(xqcScopeAnnotation.value())
&& !ScopeEnum.SINGLETON.getCode().equals(xqcScopeAnnotation.value())){
ThrowUtils.throwEx("bean scope类型不正确");
}
beanDefinition.setScope(xqcScopeAnnotation.value());
}else{
//没有写默认单例
beanDefinition.setScope(ScopeEnum.SINGLETON.getCode());
}
//生成beanDefinition
beanDefinitions.put(beanName,beanDefinition);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获取bean名称
* @param aClass
* @return
*/
private String getBeanName(Class<?> aClass) {
XqcComponent xqcComponentAnnotation = aClass.getAnnotation(XqcComponent.class);
String beanName = xqcComponentAnnotation.value();
if(beanName != null && !"".equals(beanName.trim())){
return beanName;
}
//使用类名,首字母小写
String simpleName = aClass.getSimpleName();
return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1, simpleName.length());
}
/**
* 解析入口配置类,获取包路径
* @param clazz
* @return
*/
private String getPackagePath(Class<?> clazz) {
XqcConfiguration configurationAnnotation = clazz.getAnnotation(XqcConfiguration.class);
//获取要扫描的路径
String packages = configurationAnnotation.value();
packages = packages.replace(".","/");
//读取包下面的class,真正的Spring源码用的ASM技术,这里只是简单的实现读取
ClassLoader classLoader = XqcApplicationContext.class.getClassLoader();
return classLoader.getResource(packages).getFile();
}
/**
* 获取类完整的路径,包名+类名
* @param path
* @return
*/
private String subPath(String path) {
path = path.substring(path.indexOf("classes") + 8, path.indexOf(".class")).replace("\\",".");
return path;
}
/**
* 扫描包路径
* @param classes
* @param path
*/
private static void scannerPackage(List<String> classes, String path) {
File file = new File(path);
for (File file1 : file.listFiles()) {
if (file1.isDirectory()) {
scannerPackage(classes,file1.getPath());
} else {
classes.add(file1.getPath());
}
}
}
/**
* 创建bean
* @param beanName
* @param beanDefinition
* @return
*/
public Object createBean(String beanName,XqcBeanDefinition beanDefinition){
Object bean = null;
try {
Class clazz = beanDefinition.getClazz();
bean = clazz.newInstance();
//初始化前
for (XqcBeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean,beanName);
}
for (Field field : clazz.getDeclaredFields()) {
//解析XqcValue注解
if (field.isAnnotationPresent(XqcValue.class)) {
XqcValue xqcValueAnnotation = field.getAnnotation(XqcValue.class);
field.setAccessible(true);
field.set(bean, xqcValueAnnotation.value());
}
//解析XqcAutowired注解
if (field.isAnnotationPresent(XqcAutowired.class)) {
Object bean1 = getBean(field.getType());
field.setAccessible(true);
field.set(bean, bean1);
}
}
//解析aware接口
if (bean instanceof XqcBeanAware) {
((XqcBeanAware) bean).setBeanName(beanName);
}
//解析XqcPostConstruct注解的方法
for (Method method : clazz.getDeclaredMethods()) {
//解析XqcValue注解
if (method.isAnnotationPresent(XqcPostConstruct.class)) {
method.invoke(bean, method.getTypeParameters());
}
}
//bean初始化执行
if (bean instanceof XqcInitializingBean) {
((XqcInitializingBean) bean).afterPropertiesSet();
}
//初始化后
for (XqcBeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
}
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
/**
* 获取bean
* @param beanName
* @return
*/
public Object getBean(String beanName){
XqcBeanDefinition xqcBeanDefinition = beanDefinitions.get(beanName);
if(xqcBeanDefinition == null){
ThrowUtils.throwEx("bean对象不存在");
}
String scope = xqcBeanDefinition.getScope();
if(ScopeEnum.PROTOTYPE.getCode().equals(scope)){
//原型,每次都创建
return this.createBean(beanName,beanDefinitions.get(beanName));
}
if(singletonObjects.containsKey(beanName)){
return singletonObjects.get(beanName);
}
return this.createBean(beanName, beanDefinitions.get(beanName));
}
public Object getBean(Class clazz){
return this.getBean(this.getBeanName(clazz));
}
}
测试工程,引入上面的xqc-beans工程的jar包
结果输出