执行流程

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; |
| |
| |
| |
| |
| public class ApplicationContext { |
| private ConcurrentHashMap<String, Object> singletonPool = new ConcurrentHashMap<>(); |
| |
| public ApplicationContext(Class<?> configClass) { |
| |
| String packagePath = configClass.getDeclaredAnnotation(ComponentScan.class).value(); |
| |
| |
| scanAndCreateBean(packagePath); |
| } |
| |
| private void scanAndCreateBean(String packagePath) { |
| ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| URL url = loader.getResource(packagePath.replace(".", "/")); |
| |
| |
| 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<>(); |
| |
| for (File childFile : file.listFiles()) { |
| String childFilePath = childFile.getPath(); |
| if (childFilePath.endsWith(".class")) { |
| |
| childFilePath = childFilePath.substring(childFilePath.lastIndexOf("\\") + 1, childFilePath.lastIndexOf(".")); |
| |
| classNames.add(packagePath + "." + childFilePath); |
| } |
| } |
| |
| for (String className : classNames) { |
| try { |
| Class<?> clazz = loader.loadClass(className); |
| |
| if (clazz.isAnnotationPresent(Component.class)) { |
| |
| String curClassName = className.substring(className.lastIndexOf('.') + 1); |
| String beanName = curClassName.substring(0, 1).toLowerCase() + curClassName.substring(1); |
| |
| |
| Object obj = clazz.getDeclaredConstructor().newInstance(); |
| |
| |
| for (Field declaredField : clazz.getDeclaredFields()) { |
| |
| if (declaredField.isAnnotationPresent(Autowired.class)) { |
| |
| 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()); |
| } |
| } |
执行结果

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!