手写Spring底层源码 启动扫描、依赖注入解析分享
1.通过手写模拟,了解Spring的底层源码启动过程
2.通过手写模拟,了解BeanDefinition、BeanPostProcessor的概念
3.通过手写模拟,了解Spring解析配置类等底层源码工作流程
4.通过手写模拟,了解依赖注入,Aware回调等底层源码工作流程
在手写Spring之前我们先看看 Spring一般启动都是怎么怎么对Bean进行创建的,下面的代码是正常实例化一个Spring的ApplicationContext的类 传入 Config类进去
//Test.java
public class Test1 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(Config.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test(); //执行 userService 的 text方法
}
}
//Appconfig.java
//指定要扫描的路径
@ComponentScan("com.yyge.service")
public class AppConfig {
}
// service/UserService.java
@Component("userService") //给当前Bean去取一个名字 并且为单例 Bean
@Scope("prototype") //配置为原型Bean 也就是多例Bean
public class UserService {
@Autowired
private OrderService orderService;
public void test(){
System.out.printf("输出测试");
}
}
如上代码都是我们引入了Spring之后可以直接进行的操作 让Spring帮我们去实例化Bean对象,并且可以使用这些注解,下面我们来手写模拟Spring的一些操作
一、手写ApplicationContext
我这里命名为YygeApplicationContext.java 由于代码文件有一些多不方便展示 我这里就只展示核心的YygeApplicationContext.java文件内容
/**
* 模拟spring启动类
* @author 壹影
*/
public class YygeApplicationContext {
private Class configClass; // 用于接收外面传进来的配置类
private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
private Map<String,Object> singletonObjects = new HashMap<>();
private List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>(); //用于存储BeanPostProcessor
public YygeApplicationContext(Class configClass) {
this.configClass=configClass;
//扫描
scan(configClass);
//扫描完毕之后 就回去创建单例Bean
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition=entry.getValue();
//找出所有的单例Bean
if(beanDefinition.getScope().equals("singleton")){
//找到之后去创建
Object bean =createBean(beanName,beanDefinition);
singletonObjects.put(beanName,bean); // 保存单例Bean
}
}
}
/**
* 创建Bean
* @param beanName bean的名称
* @param beanDefinition beanDefinition 对象
* @return 返回Object
*/
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class<?> clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();//获取到无参构造方法 并且去实例化
//实现依赖注入
//获取这个对象里面所有的属性 getDeclaredFields() 并且遍历
for (Field field : clazz.getDeclaredFields()) {
//判断属性上面是否存在Autowired注解
if (field.isAnnotationPresent(Autowired.class)) {
//如果存在
field.setAccessible(true); //设置可以通过反射 访问和操作类的 私有成员
//field.getName() 获取当前属性的名字 为这个字段设置值
field.set(instance,getBean(field.getName()));
}
}
// 初始化前方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
}
//初始化的实现
//判断当前实例 是否实现了InitializingBean这个接口
if (instance instanceof InitializingBean){
//如果实现了就进行强制转换 并执行afterPropertiesSet 方法
((InitializingBean) instance).afterPropertiesSet();
}
// 初始化后方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
}
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return instance;
}
/**
* 扫描类
* @param configClass
*/
private void scan(Class configClass) {
//扫描
if (configClass.isAnnotationPresent(ComponentScan.class)) {
//拿到类上面的ComponentScan注解
ComponentScan componentScanAnnotaion = (ComponentScan) configClass.getAnnotation(ComponentScan.class);//拿到注解对象
//拿到注解后 我们就可以拿到里面的扫描路径
String path = componentScanAnnotaion.value();
path = path.replace(".","/");
System.out.println("扫描路径--> "+path);
//获取当前类的类加载
ClassLoader classLoader = YygeApplicationContext.class.getClassLoader();
//获取类加载的 Resource 路径
URL resource = classLoader.getResource(path);
//定义File 传入路径 File可以是 文件 也可以表示文件夹
File file =new File(resource.getFile());
//如果是文件夹的话 就遍历他
if(file.isDirectory()){
for (File f : file.listFiles()) {
//获取 文件的绝对路径
String absolutePath = f.getAbsolutePath();
//System.out.println(absolutePath); // 打印测试看看
//将:C:\Users\Administrator\Desktop\project\spring\target\classes\com\yyge\service\OrderService.class
//截取为这样com.yyge.service.OrderService.class
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\",".");
//判断:这些文件里面有没有Component 注解
//方法 将class文件加载为class对象
try {
Class<?> clazz = classLoader.loadClass(absolutePath);
// 判断每一个类上面有没有 Component 注解
if (clazz.isAnnotationPresent(Component.class)) {
//判断当前类是否实现了BeanPostProcessor这个接口
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
BeanPostProcessor newInstance = (BeanPostProcessor) clazz.getConstructor().newInstance();
beanPostProcessorList.add(newInstance);
}
Component annotation = clazz.getAnnotation(Component.class); //取出来Component 注解
String beanName = annotation.value(); //获取annotation 注解中的值 也就是Bean的名字
//如果拿出来的名字为"" 那么就默认生成一个名字
if("".equals(beanName)){
//默认生成名字
beanName = Introspector.decapitalize(clazz.getSimpleName());
}
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setType(clazz); //记录Bean的类型
//判断Scope 注解
if (clazz.isAnnotationPresent(Scope.class)) {
//如果有的话
Scope scope = clazz.getAnnotation(Scope.class);
String value = scope.value(); // 然后拿到里面配置的内容
beanDefinition.setScope(value); // 设置作用域
} else {
// 如果没有Scope注解 默认就是单例 singleton
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName,beanDefinition);
// 创建Bean
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
}
}
public Object getBean(String beanName){
if(!beanDefinitionMap.containsKey(beanName)){
throw new RuntimeException("容器不存在的Bean:"+beanName);
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {
Object singletonBean = singletonObjects.get(beanName);
//因为在依赖注入的时候 也要调用getBean 如果说singletonBean 取出来是null 说明没有创建
//所以直接创建就可以了
if(singletonBean == null){
singletonBean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName,singletonBean);
}
//如果是单例 则从单例池中去取值
return singletonBean;
}else{
//原型bean
return createBean(beanName,beanDefinition);
}
}
}
其他文件源码附在了如下链接,下载项目打开参考
下载地址:点我跳转
提取码:评论后查看
此处内容已隐藏,评论后刷新即可查看!
我的学习
通过分析Spring的源码让我学习到了很多的内容具体有如下内容
//1.判断xxx类是否有xxxx注解
if (YygeClass.isAnnotationPresent(ComponentScan.class)) {
//判断YygeClass类是否有ComponentScan注解
}
//2.获取注解对象 类.getAnnotation(xxx.class) 需要强转
ComponentScan componentScanAnnotaion = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
//3.获取注解的属性 注解对象.属性()
componentScanAnnotaion.value();
//4.获取当前类的类加载对象 ClassLoader
ClassLoader classLoader = 当前类.class.getClassLoader();
//5.获取类加载的 Resource 路径 path可以为相对路径
URL resource = classLoader.getResource(path)
//6.通过URL对象实例化File对象 注意File可以是对象也可以是文件夹
File file =new File(resource.getFile());
//7.判断File对象是否是文件夹 返回布尔值
file.isDirectory()
//8.获取File对象的绝对路径
String absolutePath = file.getAbsolutePath()
//9.获取File对象 下所有的File对象(就是文件夹里面所有的文件 如果File是文件夹的话)
file.listFiles()
//10.判断某个类实现了某个接口
if (YygeClass.class.isAssignableFrom(BeanPostProcessor.class)) {
//判断YygeClass类是否有BeanPostProcessor接口
}
//11.通过反射实例化某个对象 --实例化后拿到的是Object 可以强转为实例的那个类
YygeClass.class.getConstructor().newInstance()
AlexisVar
2023-11-29 23:18冠天下
https://xn--ghq10gmvi.com/
SteveaBili
2023-11-26 23:19向新力運動彩券行
https://1688bet.tw/
Rodneycer
2023-11-26 23:17滿天星娛樂城
https://star168.tw/
WilliambrAsp
2023-11-24 13:26水微晶玻尿酸 - 八千代
https://yachiyo.com.tw/hyadermissmile-injection/