当前位置: 首页 > news >正文

手动模拟Spring(简易版)

目录

一:实现spring的依赖注入

1.在D盘新建文件夹project,用来做项目存放的路径

2.打开idea,通过选择 File->New->Project(文件->新建->项目),创建项目

3.选择java,更改项目名称、工作目录和JDK版本,然后点击下一步

4.新建四个包annotation、config、entity、service

5.在包annotation下面创建注解

6.在entity下面新建实体类MyBeanDefinition

7.在service下面新建业务层UserService和OrderService

8.在config下面新建MyScanConfig和MySpringApplicationContext

9.在包com.saas下新建启动类MySpringApplication

10.运行MySpringApplication

二:实现spring切面功能

1.在包service下面新建接口UserInterface,同时更改UserService实现接口

2.在包service下面新建接口MyBeanPostProcessor和实现AopBeanPostProcessor

3.修改上下文MySpringApplicationContext

4.修改启动类MySpringApplication

5.运行MySpringApplication


一:实现spring的依赖注入

1.在D盘新建文件夹project,用来做项目存放的路径

2.打开idea,通过选择 File->New->Project(文件->新建->项目),创建项目

 

3.选择java,更改项目名称、工作目录和JDK版本,然后点击下一步

4.新建四个包annotation、config、entity、service

5.在包annotation下面创建注解

package com.saas.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于需要注入的对象*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {}
package com.saas.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于管理需要注入的对象*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponent {String value() default "";
}
package com.saas.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于定义需要扫描的包路径*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponentScan {String value() default "";
}

package com.saas.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于判断对象是否是单例*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyScope {String value() default "";
}

6.在entity下面新建实体类MyBeanDefinition

package com.saas.entity;/*** 用于bean的定义*/
public class MyBeanDefinition {/*** bean类型*/private Class type;/*** bean的作用域*/private String Scope;public Class getType() {return type;}public void setType(Class type) {this.type = type;}public String getScope() {return Scope;}public void setScope(String scope) {Scope = scope;}
}

7.在service下面新建业务层UserService和OrderService

package com.saas.service;import com.saas.annotation.MyComponent;/*** 订单业务逻辑处理* 这里指定名称(可以不用)*/
@MyComponent("orderService")
public class OrderService {}
package com.saas.service;import com.saas.annotation.MyAutowired;
import com.saas.annotation.MyComponent;
import com.saas.annotation.MyScope;/*** 用户业务逻辑处理* 这里指定bean的名称(可以不用)* 注解MyScope用于判断是否单例*/
@MyComponent("userService")
//@MyScope("prototype")
public class UserService {@MyAutowiredprivate OrderService orderService;public void buy(){System.out.println("orderService:"+orderService);}}

8.在config下面新建MyScanConfig和MySpringApplicationContext

package com.saas.config;import com.saas.annotation.MyComponentScan;/*** 扫描配置类* 指定扫描路径(可以不用)*/
@MyComponentScan("com.saas.service")
public class MyScanConfig {
}

package com.saas.config;import com.saas.annotation.MyAutowired;
import com.saas.annotation.MyComponent;
import com.saas.annotation.MyComponentScan;
import com.saas.annotation.MyScope;
import com.saas.entity.MyBeanDefinition;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;/*** 模拟spring应用上下文实现类,用于管理Bean的生命周期和依赖注入*/
public class MySpringApplicationContext {/*** 配置类*/private Class configClass;/*** bean信息容器*/private ConcurrentHashMap<String, MyBeanDefinition> myBeanDefinitionMap = new ConcurrentHashMap<>();/*** 单例池*/private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();public MySpringApplicationContext(Class configClass) {//赋值配置类this.configClass = configClass;//进行扫描操作//判断是否是扫描路径注解if(configClass.isAnnotationPresent(MyComponentScan.class)){MyComponentScan myComponentScan =(MyComponentScan) configClass.getAnnotation(MyComponentScan.class);//获取扫描路径("com.saas.service")String scanPath = myComponentScan.value();ClassLoader classLoader = MySpringApplicationContext.class.getClassLoader();//获取路径,需要转换成("com/saas/service")scanPath = scanPath.replace('.', '/');URL resourceUrl = classLoader.getResource(scanPath);//获取文件File file = new File(resourceUrl.getFile());//判断是否是文件夹if(file.isDirectory()){File[] files = file.listFiles();for(File f : files){//获取文件的绝对路径String fileAbsolutePath = f.getAbsolutePath();//获取以.class后缀的文件if(fileAbsolutePath.endsWith(".class")){//获取类名称String className = fileAbsolutePath.substring(fileAbsolutePath.indexOf("com"),fileAbsolutePath.indexOf(".class")).replace("\\",".");try {Class<?> clazz = classLoader.loadClass(className);//判断类是否有需要注入的属性if(clazz.isAnnotationPresent(MyComponent.class)){MyBeanDefinition myBeanDefinition = new MyBeanDefinition();myBeanDefinition.setType(clazz);//判断是否单列if(clazz.isAnnotationPresent(MyScope.class)){MyScope myScope = clazz.getAnnotation(MyScope.class);String myScopeValue = myScope.value();myBeanDefinition.setScope(myScopeValue);}else {myBeanDefinition.setScope("singleton");}//获取bean的名称,为了放入容器里面MyComponent myComponent = clazz.getAnnotation(MyComponent.class);String beanValue = myComponent.value();//放入容器里面myBeanDefinitionMap.put(beanValue, myBeanDefinition);}} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}}}}//循环for(String beanName : myBeanDefinitionMap.keySet()){MyBeanDefinitionmyBeanDefinition = myBeanDefinitionMap.get(beanName);String scope = myBeanDefinition.getScope();if("singleton".equals(scope)){Object bean = crateBean(beanName, myBeanDefinition);//将bean放入单例池singletonObjects.put(beanName, bean);}}}/*** 通过bean名称创建一个对象* @param beanName* @param myBeanDefinition* @return*/private Object crateBean(String beanName,MyBeanDefinition myBeanDefinition){Class clazz = myBeanDefinition.getType();try {//实例化对象Object instance = clazz.getConstructor().newInstance();//遍历类的字段赋值(spring内部会根据名称或类型进行bean匹配,此处省略)for (Field field : clazz.getDeclaredFields()) {if(field.isAnnotationPresent(MyAutowired.class)){field.setAccessible(true);field.set(instance, getBean(field.getName()));}}return instance;} 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);}}/*** 通过bean的名称获取对象* @param beanName* @return*/public Object getBean(String beanName) {MyBeanDefinition myBeanDefinition = myBeanDefinitionMap.get(beanName);if(myBeanDefinition == null){throw new NullPointerException();}else {String scope = myBeanDefinition.getScope();//判断bean的作用域是否单例if("singleton".equals(scope)){Object bean = singletonObjects.get(beanName);if (bean == null) {//创建bean对象crateBean(beanName, myBeanDefinition);//将bean放入单例池singletonObjects.put(beanName, bean);}return bean;}else {//创建bean对象return crateBean(beanName, myBeanDefinition);}}}
}

9.在包com.saas下新建启动类MySpringApplication

package com.saas;import com.saas.config.MyScanConfig;
import com.saas.config.MySpringApplicationContext;
import com.saas.service.UserService;/*** spring启动类*/
public class MySpringApplication {public static void main(String[] args) {MySpringApplicationContext applicationContext = new MySpringApplicationContext(MyScanConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.buy();}}

10.运行MySpringApplication

二:实现spring切面功能

1.在包service下面新建接口UserInterface,同时更改UserService实现接口

package com.saas.service;/*** 用户逻辑的代理对象*/
public interface UserInterface {public void buy();
}
package com.saas.service;import com.saas.annotation.MyAutowired;
import com.saas.annotation.MyComponent;
import com.saas.annotation.MyScope;/*** 用户业务逻辑处理* 这里指定bean的名称(可以不用)* 注解MyScope用于判断是否单例*/
@MyComponent("userService")
//@MyScope("prototype")
public class UserService implements UserInterface{@MyAutowiredprivate OrderService orderService;public void buy(){System.out.println("orderService:"+orderService);}}

2.在包service下面新建接口MyBeanPostProcessor和实现AopBeanPostProcessor

package com.saas.service;public interface MyBeanPostProcessor {public Object postProcessBeforeInitialization(String beanName, Object bean);public Object postProcessAfterInitialization(String beanName, Object bean);
}
package com.saas.service;import com.saas.annotation.MyComponent;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;@MyComponent
public class AopBeanPostProcessor implements MyBeanPostProcessor{/*** 前置处理* @param beanName* @param bean* @return*/@Overridepublic Object postProcessBeforeInitialization(String beanName, Object bean) {//写死是userService才处理if("userService".equals(beanName)){System.out.println("=========我是前置======");}return bean;}/*** 后置处理* @param beanName* @param bean* @return*/@Overridepublic Object postProcessAfterInitialization(String beanName, Object bean) {//写死是userService才处理if("userService".equals(beanName)){System.out.println("=========我是后置======");Object proxy = Proxy.newProxyInstance(AopBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("=========切面逻辑处理======");return method.invoke(bean, args);}});return proxy;}return bean;}
}

3.修改上下文MySpringApplicationContext

package com.saas.config;import com.saas.annotation.MyAutowired;
import com.saas.annotation.MyComponent;
import com.saas.annotation.MyComponentScan;
import com.saas.annotation.MyScope;
import com.saas.entity.MyBeanDefinition;
import com.saas.service.MyBeanPostProcessor;import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** 模拟spring应用上下文实现类,用于管理Bean的生命周期和依赖注入*/
public class MySpringApplicationContext {/*** 配置类*/private Class configClass;/*** bean信息容器*/private ConcurrentHashMap<String, MyBeanDefinition> myBeanDefinitionMap = new ConcurrentHashMap<>();/*** 单例池*/private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();/*** bean处理器容器*/private List<MyBeanPostProcessor> myBeanPostProcessors = new ArrayList<>();public MySpringApplicationContext(Class configClass) {//赋值配置类this.configClass = configClass;//进行扫描操作//判断是否是扫描路径注解if(configClass.isAnnotationPresent(MyComponentScan.class)){MyComponentScan myComponentScan =(MyComponentScan) configClass.getAnnotation(MyComponentScan.class);//获取扫描路径("com.saas.service")String scanPath = myComponentScan.value();ClassLoader classLoader = MySpringApplicationContext.class.getClassLoader();//获取路径,需要转换成("com/saas/service")scanPath = scanPath.replace('.', '/');URL resourceUrl = classLoader.getResource(scanPath);//获取文件File file = new File(resourceUrl.getFile());//判断是否是文件夹if(file.isDirectory()){File[] files = file.listFiles();for(File f : files){//获取文件的绝对路径String fileAbsolutePath = f.getAbsolutePath();//获取以.class后缀的文件if(fileAbsolutePath.endsWith(".class")){//获取类名称String className = fileAbsolutePath.substring(fileAbsolutePath.indexOf("com"),fileAbsolutePath.indexOf(".class")).replace("\\",".");try {Class<?> clazz = classLoader.loadClass(className);//判断类是否有需要注入的属性if(clazz.isAnnotationPresent(MyComponent.class)){//判断扫描路径下有实现了MyBeanPostProcessor接口的类if(MyBeanPostProcessor.class.isAssignableFrom(clazz)){MyBeanPostProcessor myBeanPostProcessor = (MyBeanPostProcessor) clazz.newInstance();myBeanPostProcessors.add(myBeanPostProcessor);}MyBeanDefinition myBeanDefinition = new MyBeanDefinition();myBeanDefinition.setType(clazz);//判断是否单列if(clazz.isAnnotationPresent(MyScope.class)){MyScope myScope = clazz.getAnnotation(MyScope.class);String myScopeValue = myScope.value();myBeanDefinition.setScope(myScopeValue);}else {myBeanDefinition.setScope("singleton");}//获取bean的名称,为了放入容器里面MyComponent myComponent = clazz.getAnnotation(MyComponent.class);String beanValue = myComponent.value();//如果获取为空则赋值if("".equals(beanValue)){beanValue = Introspector.decapitalize(clazz.getSimpleName());}//放入容器里面myBeanDefinitionMap.put(beanValue, myBeanDefinition);}} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}}}}//循环for(String beanName : myBeanDefinitionMap.keySet()){MyBeanDefinitionmyBeanDefinition = myBeanDefinitionMap.get(beanName);String scope = myBeanDefinition.getScope();if("singleton".equals(scope)){Object bean = crateBean(beanName, myBeanDefinition);//将bean放入单例池singletonObjects.put(beanName, bean);}}}/*** 通过bean名称创建一个对象* @param beanName* @param myBeanDefinition* @return*/private Object crateBean(String beanName,MyBeanDefinition myBeanDefinition){Class clazz = myBeanDefinition.getType();try {//实例化对象Object instance = clazz.getConstructor().newInstance();//遍历类的字段赋值(spring内部会根据名称或类型进行bean匹配,此处省略)for (Field field : clazz.getDeclaredFields()) {if(field.isAnnotationPresent(MyAutowired.class)){field.setAccessible(true);field.set(instance, getBean(field.getName()));}}//调用前置和后置方法for (MyBeanPostProcessor myBeanPostProcessor : myBeanPostProcessors) {instance = myBeanPostProcessor.postProcessBeforeInitialization(beanName, instance);}for (MyBeanPostProcessor myBeanPostProcessor : myBeanPostProcessors) {instance = myBeanPostProcessor.postProcessAfterInitialization(beanName, instance);}return instance;} 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);}}/*** 通过bean的名称获取对象* @param beanName* @return*/public Object getBean(String beanName) {MyBeanDefinition myBeanDefinition = myBeanDefinitionMap.get(beanName);if(myBeanDefinition == null){throw new NullPointerException();}else {String scope = myBeanDefinition.getScope();//判断bean的作用域是否单例if("singleton".equals(scope)){Object bean = singletonObjects.get(beanName);if (bean == null) {//创建bean对象crateBean(beanName, myBeanDefinition);//将bean放入单例池singletonObjects.put(beanName, bean);}return bean;}else {//创建bean对象return crateBean(beanName, myBeanDefinition);}}}
}

4.修改启动类MySpringApplication

package com.saas;import com.saas.config.MyScanConfig;
import com.saas.config.MySpringApplicationContext;
import com.saas.service.UserInterface;
import com.saas.service.UserService;/*** spring启动类*/
public class MySpringApplication {public static void main(String[] args) {MySpringApplicationContext applicationContext = new MySpringApplicationContext(MyScanConfig.class);UserInterface userService = (UserInterface) applicationContext.getBean("userService");userService.buy();}}

5.运行MySpringApplication

http://www.dtcms.com/a/596453.html

相关文章:

  • 蓝牙钥匙 第88次 蓝牙钥匙未来发展趋势篇:用户体验未来趋势深度解析
  • jmeter集群压测配置方法和注意事项
  • [笔记]SolidWorks转URDF 在rviz2中显示
  • 抖音商城店铺用户体验优化研究(开题报告)
  • 北京网站推广公司排名永久免费的cms系统带商城
  • STM32外设学习--USART串口协议--学习笔记。
  • 汉狮做网站公司郑州苏州建设网站的网络公司
  • 【C#-sqlSugar-sqlite】在Windows从源码编译构建System.Data.SQLite.dll的方法
  • 【WPF】WrapPanel的用法
  • wpf 控件中Margin属性如何设置绑定?
  • 【管综】考研199管理类联考真题试卷及答案解析PDF电子版(2009-2025年)
  • UDP/TCP接收/转发/广播服务端
  • WPF 获取鼠标相对于控件的坐标信息,控制控件锚点放缩
  • 面试题—linux
  • 福田皇岗社区做网站网页制作怎么收费
  • 236. Java 集合 - 使用索引访问 List 元素
  • 天河网站建设哪家强华为企业邮箱
  • 基于Java的电影管理系统的设计与实现
  • C#初级面试题5、拆箱和装箱
  • 如何判断企业是否需要 IAM ?数字化转型中的权限治理自测
  • CSP-J教程——第一阶段——第六课:程序流程控制 - 循环结构(一)for循环
  • 【C++基础与提高】第二章:C++数据类型系统——构建程序的基础砖石
  • 【每天一个知识点】CAG:Context-Augmented Generation
  • 《Linux系统编程之系统导论》【冯诺依曼体系结构 + 操作系统基本概述】
  • 第23天python内容
  • 5.2、Python-字符串的编码和解码
  • 美容院网站源码网站流量下降的原因
  • FreeRTOS 学习:(十七)“外部中断”和“内核中断”的差异,引入 FreeRTOS 中断管理
  • CodeBuddy AI IDE :Skills 模式
  • 大模型学习计划(按周规划)