手动模拟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

