Spring IoC常用注解手写实现

执行流程

1.    初始化Spring容器时传入配置类,通过配置类的@ComponentScan注解告知Spring需要扫描的包路径,不在扫描包路径下的@Component等注解修饰的Bean不会被IoC容器创建;
2.    从工程根目录/target/classes中获取全类名,使用类加载器加载全类名得到class对象;
3.    通过无参构造函数来实例化单例bean并放入单例池中,beanName默认是类名首字母小写;
4.    调用getBean方法时根据beanName从单例池中获取Bean。

代码(注解类忽略)

Address类

package com.wjq.bean;
import com.wjq.myspring.annotation.Component;
@Component("address")
public class Address {
public String getAddressStr() {
return "北京";
}
}

User类

package com.wjq.bean;
import com.wjq.myspring.annotation.Autowired;
import com.wjq.myspring.annotation.Component;
@Component
public class User {
@Autowired
private Address address;
public String getAddressStr() {
return address.getAddressStr();
}
}

ApplicationConfig类

package com.wjq.myspring;
import com.wjq.myspring.annotation.ComponentScan;
/**
* 配置类,告知扫描的包路径
*/
@ComponentScan("com.wjq.bean")
public class ApplicationConfig {
}

ApplicationContext类

package com.wjq.myspring;
import com.wjq.myspring.annotation.Autowired;
import com.wjq.myspring.annotation.Component;
import com.wjq.myspring.annotation.ComponentScan;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* Spring容器类
*/
public class ApplicationContext {
private ConcurrentHashMap<String, Object> singletonPool = new ConcurrentHashMap<>();
public ApplicationContext(Class<?> configClass) {
// 解析配置类上的@ComponentScan注解,获取扫描的包路径com.wjq.bean
String packagePath = configClass.getDeclaredAnnotation(ComponentScan.class).value();
// 扫描并创建Bean
scanAndCreateBean(packagePath);
}
private void scanAndCreateBean(String packagePath) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL url = loader.getResource(packagePath.replace(".", "/"));
// filePath是com.wjq.bean下java文件编译后生成的class文件所在的绝对路径
String filePath;
try {
filePath = URLDecoder.decode(url.getFile(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
File file = new File(filePath);
List<String> classNames = new ArrayList<>();
// 从target/classes中获取全类名
for (File childFile : file.listFiles()) {
String childFilePath = childFile.getPath();
if (childFilePath.endsWith(".class")) {
// \\表示\
childFilePath = childFilePath.substring(childFilePath.lastIndexOf("\\") + 1, childFilePath.lastIndexOf("."));
// childFilePath结果是全类名com.wjq.bean.Address和com.wjq.bean.User
classNames.add(packagePath + "." + childFilePath);
}
}
for (String className : classNames) {
try {
Class<?> clazz = loader.loadClass(className);
// 判断类上是否有@Component注解
if (clazz.isAnnotationPresent(Component.class)) {
// 类名首字母小写作为beanName
String curClassName = className.substring(className.lastIndexOf('.') + 1);
String beanName = curClassName.substring(0, 1).toLowerCase() + curClassName.substring(1);
// 通过无参构造函数来创建bean
Object obj = clazz.getDeclaredConstructor().newInstance();
// 依赖注入
for (Field declaredField : clazz.getDeclaredFields()) {
// 判断成员变量是否有@Autowired注解
if (declaredField.isAnnotationPresent(Autowired.class)) {
// 根据beanName获取对应bean
Object fieldBean = getBean(declaredField.getName());
declaredField.setAccessible(true);
declaredField.set(obj, fieldBean);
}
}
singletonPool.put(beanName, obj);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public Object getBean(String beanName) {
if (singletonPool.containsKey(beanName)) {
return singletonPool.get(beanName);
}
throw new RuntimeException("bean not exist");
}
}

Main类

import com.wjq.bean.User;
import com.wjq.myspring.ApplicationConfig;
import com.wjq.myspring.ApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(ApplicationConfig.class);
User user = (User) applicationContext.getBean("user");
System.out.println(user.getAddressStr());
}
}

执行结果

posted on   王景迁  阅读(56)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

点击右上角即可分享
微信分享提示