# MySpring **Repository Path**: wangfugui-ma/mySpring ## Basic Information - **Project Name**: MySpring - **Description**: 手写(抄袭)spring框架 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2023-01-14 - **Last Updated**: 2023-12-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: Spring ## README # 这篇博客实现了一个简单版本的Spring,主要包括Spring的Ioc和Aop功能 @[toc] ## 🚀@ComponentScan注解 > ComponentScan做的事情就是告诉Spring从哪里找到bean ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ComponentScan { String[] value() default {}; } ``` ## ✈️@Component注解 > @Component是spring中的一个注解,它的作用就是实现bean的注入 ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component { String value() default ""; } ``` ## 🚁在spring中ioc容器的类是ApplicationContext > 所以我们需要创建一个ApplicationContext,有参构造传入config的class ```java public class ApplicationContext { public ApplicationContext(Class configClass) { } } ``` > 存放bean的map ```java public class ApplicationContext { private final Map singletonObjects = new ConcurrentHashMap<>(256); public ApplicationContext(Class configClass) { } } ``` > 拿到ComponentScan的值 ```java public class ApplicationContext { private final Map singletonObjects = new ConcurrentHashMap<>(256); public ApplicationContext(Class configClass) { //查看是否有ComponentScan注解 if (configClass.isAnnotationPresent(ComponentScan.class)) { ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class); String[] paths = componentScanAnnotation.value(); } } } ``` > 拿到该路径下所有的class文件 ```java public class ApplicationContext { private final Map singletonObjects = new ConcurrentHashMap<>(256); public ApplicationContext(Class configClass) { //查看是否有ComponentScan注解 if (configClass.isAnnotationPresent(ComponentScan.class)) { ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class); String[] paths = componentScanAnnotation.value(); for (String path : paths) { //拿到包路径 ClassLoader classLoader = ApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path.replace(".", "/")); //拿到该路径下所有的class文件 File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { } } } } } } ``` > 注册有Component注解的bean ```java public class ApplicationContext { private final Map singletonObjects = new ConcurrentHashMap<>(256); public ApplicationContext(Class configClass) { //查看是否有ComponentScan注解 if (configClass.isAnnotationPresent(ComponentScan.class)) { ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class); String[] paths = componentScanAnnotation.value(); for (String path : paths) { //拿到包路径 ClassLoader classLoader = ApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path.replace(".", "/")); //拿到该路径下所有的class文件 File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { try { String filePath = f.getPath(); //拿到com.masiyi.service.MySpringConfig String sub = filePath.substring(filePath.indexOf("com"), filePath.indexOf(".class")); String classes = sub.replace("\\", "."); Class aClass = classLoader.loadClass(classes); //注册有Component注解的bean if (aClass.isAnnotationPresent(Component.class)) { Object bean = aClass.getDeclaredConstructor().newInstance(); Component component = aClass.getAnnotation(Component.class); String beanName = component.value(); if ("".equals(beanName) || beanName == null) { singletonObjects.put(f.getName().split("\\.")[0], bean); } else { singletonObjects.put(beanName, bean); } } } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) { e.printStackTrace(); } } } } } } } ``` ## 🚂测试类 > 现在我们最基础的spring的ioc已经基本实现了,我们新建一个测试类来测试 ```java public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ApplicationContext(MySpringConfig.class); } } ``` ## 🚊MySpringConfig类,统一的配置类 ```java @ComponentScan("com.masiyi.service") public class MySpringConfig { } ``` ## 🚞OrderService类,一个普通的bean ```java @Component public class OrderService { } ``` ### 🚲来测试一下功能 > 拿到包路径 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2b193d046fa84871924b31d27f66fec5.png) > 拿到该路径下所有的class文件 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a6ab379efa0e467caebbcfe077c45c9a.png) > 注册有Component注解的bean ![在这里插入图片描述](https://img-blog.csdnimg.cn/676c555bdbbc4338837d2e6850bd9a98.png) > 注册进ioc ![在这里插入图片描述](https://img-blog.csdnimg.cn/c3570e8cd8464938aa4052592d7785d1.png) > getBean方法 ```java public Object getBean(String beanName) { return this.singletonObjects.get(beanName); } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/16652c9b03224132b431f6a391c0a724.png) ## 🚡@Scope注解 > @Scope注解是 Spring IOC 容器中的一个作用域 ## 🚟BeanDefinition 类 > BeanDefinition 是定义 Bean 的配置元信息接口,可以理解为创建bean过程中的一个中间类,扩展bean,存储更多的信息 ```java public class BeanDefinition { private String scope; private Class aClass; public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public Class getaClass() { return aClass; } public void setaClass(Class aClass) { this.aClass = aClass; } } ``` ### 🚠要实现我们的@scope注解,我们需要改造一下我们的代码 > 把createBean方法抽离出来 ```java private void createBean(String beanName,Class aClass){ //注册有Component注解的bean if (aClass.isAnnotationPresent(Component.class)) { Component component = aClass.getAnnotation(Component.class); BeanDefinition beanDefinition = new BeanDefinition(); if (aClass.isAnnotationPresent(Scope.class)) { Scope scope = aClass.getAnnotation(Scope.class); beanDefinition.setScope(scope.value()); } else { beanDefinition.setScope("singleton"); } beanDefinition.setaClass(aClass); String value = component.value(); if ("".equals(value)) { beanDefinitionMap.put(beanName, beanDefinition); } else { beanDefinitionMap.put(value, beanDefinition); } } } ``` > 扫描ComponentScan注解的方法体改一下 ### 🚜然后我们从beanDefinitionMap中实例化bean ```java //将bean实例化到一级缓存中 for (String beanName : beanDefinitionMap.keySet()) { BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); //单例 if ("singleton".equals(beanDefinition.getScope())) { try { Object bean = beanDefinition.getaClass().getDeclaredConstructor().newInstance(); singletonObjects.put(beanName, bean); } catch (Exception e) { e.printStackTrace(); } } } ``` > getBean方法也需要改造 ```java public Object getBean(String beanName) { BeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName); if (beanDefinition == null) { throw new NullPointerException(); } if ("singleton".equals(beanDefinition.getScope())) { //如果是单例,直接返回缓存里的bean return this.singletonObjects.get(beanName); } else { try { //如果是多例,直接返回新的bean return beanDefinition.getaClass().getDeclaredConstructor().newInstance(); } catch (Exception e) { e.printStackTrace(); } } return null; } ``` ### 🚙我们来看一下效果 ![在这里插入图片描述](https://img-blog.csdnimg.cn/94f636ff14094f0183646263bf217f91.png) > 这是没有加scope注解 ![在这里插入图片描述](https://img-blog.csdnimg.cn/fb99b6b1c8ab41c7a270d2982ebfea54.png) **返回的bean都是一个对象** > 我们给bean加上scope注解 ![在这里插入图片描述](https://img-blog.csdnimg.cn/0317a4835e554b849dd4f9f748ec63de.png) **返回来的bean每个都不一样** ![在这里插入图片描述](https://img-blog.csdnimg.cn/7f61728362614cf99dade7d26a082f01.png) ## 🚘@Autowired注解 > spring中实现依赖注入的注解 ```java @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { } ``` ## 🚗UserService类,orderservice注入该类 ```java @Component("userService") public class UserService { } ``` ```java @Component public class OrderService { @Autowired private UserService userService; public UserService getUserService() { return userService; } } ``` ### 🚗要使@Autowired注解生效,将bean实例化到一级缓存中方法需要改造一下 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8e642ab25d054c87a09fb958fd676ad3.png) > 新增populateBean方法,用来初始bean ```java private void populateBean(Object bean, Class aClass) { Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { if (declaredField.isAnnotationPresent(Autowired.class)) { declaredField.setAccessible(true); try { declaredField.set(bean, getBean(declaredField.getName())); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } ``` > getBean方法也需要改造一下 ![在这里插入图片描述](https://img-blog.csdnimg.cn/daf585c96dfc41b1b6333ad5f3ad1750.png) > 这样我们的orderservice里面的userservice就有值了 ![在这里插入图片描述](https://img-blog.csdnimg.cn/931f3ba97037466585f5ffc63d438097.png) ## 🚕BeanPostProcessor接口 > 该接口在显示调用初始化方法的前后添加我们自己的逻辑 ```java public interface BeanPostProcessor { /** * 之前 * @param bean * @param beanName * @return */ default Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } /** * 之后 * @param bean * @param beanName * @return */ default Object postProcessAfterInitialization(Object bean, String beanName) { return bean; } } ``` > 我们创建存储BeanPostProcessor的list ![在这里插入图片描述](https://img-blog.csdnimg.cn/cc4bbe367878431fad8ec875dbf615f8.png) > 在扫描的时候添加BeanPostProcessor ![在这里插入图片描述](https://img-blog.csdnimg.cn/9782ed3d16d0497e8e30695fd01b8ca4.png) ## 🚖添加自己的BeanPostProcessor ```java @Component public class OrderPostProcessor implements BeanPostProcessor { /** * 之前 * * @param bean * @param beanName * @return */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println(beanName+"执行前"); return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } /** * 之后 * * @param bean * @param beanName * @return */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println(beanName+"执行后"); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } } ``` > 实例化的时候执行BeanPostProcessor逻辑 ![在这里插入图片描述](https://img-blog.csdnimg.cn/42361a50caeb4feea665d105730d0465.png) > 运行结果 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e2fa57fb843046bc93f375aba4cf3c4c.png) ## 🚛Aop > jdk的动态代理是基于接口生成的代理对象 ```java public interface OrderInterface { void test(); } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/4bc7f54169e84d359cbdd8d07cf85cd2.png) > 在OrderPostProcessor类中加以改造 ![在这里插入图片描述](https://img-blog.csdnimg.cn/94a08ad193404b65abf09e7f0c289afc.png) > 这样我们就可以动态代理切入我们的orderservice类 ![在这里插入图片描述](https://img-blog.csdnimg.cn/73c50c535ef945869535c69113c500fe.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/bbaf33a8344c4441a0e2ce5374c27fa2.png) **以上就是全部内容** **实现了以下** - 🚀@ComponentScan注解 - ✈️@Component注解 - 🚁ApplicationContext类 - 🚡@Scope注解 - 🚟BeanDefinition 类 - 🚘@Autowired注解 - 🚕BeanPostProcessor接口 - 🚛Aop 内容,完成了一个超级简单且基础的spring源码 > **[项目源码 ](https://gitee.com/WangFuGui-Ma/mySpring/tree/1.0.0/)** **博客码了两天,创作不易,多多点赞** ![在这里插入图片描述](https://img-blog.csdnimg.cn/e6d9d7ebb1004b3984176047fbd6080f.jpeg)