🎄欢迎来到@边境矢梦°的csdn博文🎄
🎄本文主要梳理手动实现Spring底层机制🎄
🌈我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生🌈
🎆喜欢的朋友可以关注一下🫰🫰🫰,下次更新不迷路🎆
Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大)🌑🌒🌓🌔🌕
目录
实现任务阶段 1- 编写自己 Spring 容器,实现扫描包, 得到 bean 的 class 对象
实现任务阶段 2- 扫描将 bean 信息封装到 BeanDefinition 对象, 并放入到 Map
实现任务阶段 3- 初始化 bean 单例池,并完成 getBean 方法 , createBean 方法
实现任务阶段 4- 完成依赖注入
实现任务阶段 5- bean 后置处理器实现
实现任务阶段 6- AOP 机制实现
我把下面的代码放到了GitHub托管平台上了, 如果有需要的童鞋可以去取https://github.com/luoxiongbo/code.git
1. 先用maven将项目框架搭起来, 大致的包结构
2. 在annotation包下创建ComponentScan 和 Component 注解
import com.lxbStu.spring.annotation.ComponentScan; @ComponentScan(value = "com.lxbStu.spring.component") public class LxbSpringConfig { }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Component { String value() default ""; }
3. 在ioc包下创建要给配置配LxbSpringConfig, 充当.xml的作用
@ComponentScan(value = "com.lxbStu.spring.component") public class LxbSpringConfig { }
4. 在component包下创建bean
@Component("monsterService") public class MonsterService { }
@Component("monsterDao") public class MonsterDao { }
5. 在ioc包下创建我们自己写的ClassPathXmlApplicationContext
public class LxbSpringApplicationContext { private Class config; private final ConcurrentHashMapsingleton = new ConcurrentHashMap<>(); public ConcurrentHashMap getIoc() { return singleton; } public Object getBean(String bean) { return singleton.get(bean); } public LxbSpringApplicationContext(Class ClassConfig) { this.config = ClassConfig; ComponentScan component = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class); String path = component.value(); path = path.replace(".", "/"); System.out.println("扫描的路径是 : " + path); System.out.println("====================================================="); ClassLoader classLoader = LxbSpringApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path); //System.out.println(resource); File ComponentFile = new File(resource.getFile()); if(ComponentFile.isDirectory()) { File[] files = ComponentFile.listFiles(); for (File file : files) { String classPath = file.getAbsolutePath(); System.out.println("类的绝对路径是 : " + classPath); if(classPath.endsWith(".class")) { String className = classPath.substring(classPath.lastIndexOf("\\") + 1, classPath.indexOf(".class")); String classFullPath = path.replace("/", ".") + "." + className; System.out.println("类的全路径是 :" + classFullPath + ", 类名是 :" + className); try { Class> clazz = Class.forName(classFullPath); if(clazz.isAnnotationPresent(Component.class)) { Component beanId = clazz.getDeclaredAnnotation(Component.class); String value = beanId.value(); if(value == null || "".equals(value)) { value = className.substring(0, 1).toLowerCase() + className.substring(1); } //System.out.println(value); System.out.println("是一个 bean = " + clazz); try { Object instance = clazz.newInstance(); singleton.put(value, instance); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } else { System.out.println("不是一个 bean = " + clazz); } System.out.println("====================================================="); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } } } } }
6. 测试
public class SpringTest { @Test public void ConfigTest() { LxbSpringApplicationContext ioc = new LxbSpringApplicationContext(LxbSpringConfig.class); //ConcurrentHashMapbeans = ioc.getIoc(); //Enumeration keys = beans.keys(); //while (keys.hasMoreElements()) { // String id = keys.nextElement(); // System.out.println(beans.get(id)); //} } }
结果 :
扫描的路径是 : com/lxbStu/spring/component
=====================================================
类的绝对路径是 : D:\code\java\lxb-spring\target\classes\com\lxbStu\spring\component\Car.class
类的全路径是 :com.lxbStu.spring.component.Car, 类名是 :Car
是一个 bean = class com.lxbStu.spring.component.Car
=====================================================
类的绝对路径是 : D:\code\java\lxb-spring\target\classes\com\lxbStu\spring\component\MonsterDao.class
类的全路径是 :com.lxbStu.spring.component.MonsterDao, 类名是 :MonsterDao
是一个 bean = class com.lxbStu.spring.component.MonsterDao
=====================================================
类的绝对路径是 : D:\code\java\lxb-spring\target\classes\com\lxbStu\spring\component\MonsterService.class
类的全路径是 :com.lxbStu.spring.component.MonsterService, 类名是 :MonsterService
是一个 bean = class com.lxbStu.spring.component.MonsterService
=====================================================
1. 在annotation中创建Scope, 用来注解类是单例还是多例
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Scope { String value(); }
2. 修改component包中的MonsterService
@Component("monsterService") @Scope("prototype") public class MonsterService{}
3. 在ioc中创建BeanDefinition, 用于存放bean的元数据, bean类的数据
public class BeanDefinition { private Class clazz; private String scope; public void setClazz(Class clazz) { this.clazz = clazz; } public void setScope(String scope) { this.scope = scope; } public Class getClazz() { return clazz; } public String getScope() { return scope; } @Override public String toString() { return "BeanDefinition{" + "clazz=" + clazz + ", scope=" + scope + '}'; } }
4. 重新写LxbSpringApplicationContext, 将bean的定义放到beanDefinitionMap中
public class LxbSpringApplicationContext { // 配置类 private Class config; // 存放单例bean的map private final ConcurrentHashMapsingleton = new ConcurrentHashMap<>(); // 存放bean元数据的map private final ConcurrentHashMap beanDefinitionMap = new ConcurrentHashMap<>(); // 返回单例map public ConcurrentHashMap getIoc() { return singleton; } // 返回bean根据 id public Object getBean(String bean) { return singleton.get(bean); } // 将从包中扫描类的步骤封装起来, 封装到这个方法中 public void LoaderResourceByConfig(Class ClassConfig) { this.config = ClassConfig; ComponentScan component = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class); String path = component.value(); path = path.replace(".", "/"); System.out.println("扫描的路径是 : " + path); System.out.println("====================================================="); ClassLoader classLoader = LxbSpringApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path); //System.out.println(resource); File ComponentFile = new File(resource.getFile()); if (ComponentFile.isDirectory()) { File[] files = ComponentFile.listFiles(); for (File file : files) { String classPath = file.getAbsolutePath(); System.out.println("类的绝对路径是 : " + classPath); if (classPath.endsWith(".class")) { String className = classPath.substring(classPath.lastIndexOf("\\") + 1, classPath.indexOf(".class")); String classFullPath = path.replace("/", ".") + "." + className; System.out.println("类的全路径是 :" + classFullPath + ", 类名是 :" + className); try { Class> clazz = Class.forName(classFullPath); if (clazz.isAnnotationPresent(Component.class)) { Component beanId = clazz.getDeclaredAnnotation(Component.class); String id = beanId.value(); if (id == null || "".equals(id)) { id = className.substring(0, 1).toLowerCase() + className.substring(1); } //System.out.println(value); System.out.println("是一个 bean = " + clazz); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); if (clazz.isAnnotationPresent(Scope.class)) { Scope scope = clazz.getDeclaredAnnotation(Scope.class); beanDefinition.setScope(scope.value()); } else { beanDefinition.setScope("singleton"); } beanDefinitionMap.put(id, beanDefinition); } else { System.out.println("不是一个 bean = " + clazz); } System.out.println("====================================================="); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } } } } // 构造器, 参数是配置类 public LxbSpringApplicationContext(Class ClassConfig) { LoaderResourceByConfig(ClassConfig); } }
结果 :
1. 将bean根据单例还是多例进行实例化, 将单例进行实例化放到singletonMap中, 多例不进行实例化
// 返回bean根据 id public Object getBean(String bean) { if(beanDefinitionMap.containsKey(bean)) { BeanDefinition beanDefinition = beanDefinitionMap.get(bean); if(beanDefinition.getScope().equals("singleton")) { return singletonMap.get(bean); } else { return create(bean); } } else { throw new NullPointExecption("不存在的bean"); } } public Object createBean(BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); try { return clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } }
2. 测试类Test
public class SpringTest { @Test public void ConfigTest() { LxbSpringApplicationContext ioc = new LxbSpringApplicationContext(LxbSpringConfig.class); System.out.println("====================================================="); ConcurrentHashMapbeans = ioc.getIoc(); Enumeration keys = beans.keys(); while (keys.hasMoreElements()) { String id = keys.nextElement(); System.out.println(beans.get(id)); } } }
结果 :
1. 在annotation中创建注解Autowired
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.FIELD}) public @interface Autowired { //一个属性 required ,这里我们就不讲了,也比较简单, 有兴趣同学们作为课后加入 //String required() default "true"; }
2. 修改component中的MonsterService和MonsterDao
@Component("monsterDao") public class MonsterDao { public void hi() { System.out.println("喵喵喵~~~"); } }
@Scope("prototype") @Component("monsterService") public class MonsterService { @Autowired private MonsterDao monsterDao; public void m1() { monsterDao.hi(); } }
3. 修改LxbSpringApplicationContext, 中的createBean方法, 在实例化对象的时候将域中需要注入的属性进行注入
public Object createBean(BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); Object instance = null; try { instance = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { Object bean = getBean(declaredField.getName()); try { declaredField.set(instance, bean); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } return instance; }
结果 :
原因分析 :
修改如下图 :
结果 :
1. 对于初始化方法, 我们写一个接口InitializingBean, 如果一个类实现了就说明bean含有初始化方法, 反之, 亦然.
public interface InitializingBean { void afterPropertiesSet() throws Exception; }
2. 修改 MonsterDao 类, 实现接口 InitializingBean , 实现它的方法, 让该类有初始化方法
@Component("monsterDao") public class MonsterDao implements InitializingBean { public void hi() { System.out.println("喵喵喵~~~"); } /** * 就像之前那样, 我们是通过写一个方法在xml中配置属性的时候给初始化的属性进行赋值 * 初始化方法可有可无, 但是后置处理器是 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { System.out.println("MonsterService 进行初始化, 具体业务由程序员来搞定...."); } }
3. 先用简单的步骤测试实现方法的类在create的时候会不会执行初始化方法
public Object createBean(BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); Object instance = null; try { instance = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { Object bean = getBean(declaredField.getName()); try { declaredField.setAccessible(true); declaredField.set(instance, bean); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } System.out.println("=====================创建好了实例======================"); if(instance instanceof InitializingBean) { try { ((InitializingBean) instance).afterPropertiesSet(); } catch (Exception e) { throw new RuntimeException(e); } } return instance; }
结果 :
4. 后置处理器接口的实现, 在processe中进行创建
public interface BeanPostProcessor { //bean 初始化前执行的业务 Object postProcessBeforeInitialization(Object bean, String beanName); //bean 初始化后执行的业务 Object postProcessAfterInitialization(Object bean, String beanName); }
5. 在component中创建LxbBeanPostProcessor, 用来进行后置处理
@Component public class LxbBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("postProcessBeforeInitialization 被调用 " + beanName + " bean= " + bean.getClass()); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("postProcessAfterInitialization 被调用 " + beanName + " bean= " + bean.getClass()); return bean; } }
6. 修改ioc的SpringApplicationContext中的扫描方法和createBean() 方法, 在扫描的时候将他们进行实例化并放到beanPostProcessorMap中, 在create的时候调用所有的后置处理器
扫描方法
public void LoaderResourceByConfig(Class ClassConfig) throws RuntimeException { this.config = ClassConfig; ComponentScan component = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class); String path = component.value(); path = path.replace(".", "/"); System.out.println("扫描的路径是 : " + path); System.out.println("====================================================="); ClassLoader classLoader = LxbSpringApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path); //System.out.println(resource); File ComponentFile = new File(resource.getFile()); if (ComponentFile.isDirectory()) { File[] files = ComponentFile.listFiles(); for (File file : files) { String classPath = file.getAbsolutePath(); System.out.println("类的绝对路径是 : " + classPath); if (classPath.endsWith(".class")) { String className = classPath.substring(classPath.lastIndexOf("\\") + 1, classPath.indexOf(".class")); String classFullPath = path.replace("/", ".") + "." + className; System.out.println("类的全路径是 :" + classFullPath + ", 类名是 :" + className); try { Class> clazz = Class.forName(classFullPath); if (clazz.isAnnotationPresent(Component.class)) { Component beanId = clazz.getDeclaredAnnotation(Component.class); String id = beanId.value(); if (id == null || "".equals(id)) { id = className.substring(0, 1).toLowerCase() + className.substring(1); } //System.out.println(value); System.out.println("是一个 bean = " + clazz); if(clazz.isAssignableFrom(BeanPostProcessor.class)) { BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.newInstance(); beanPostProcessorList.add(beanPostProcessor); continue; } BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); if (clazz.isAnnotationPresent(Scope.class)) { Scope scope = clazz.getDeclaredAnnotation(Scope.class); beanDefinition.setScope(scope.value()); } else { beanDefinition.setScope("singleton"); } beanDefinitionMap.put(id, beanDefinition); } else { System.out.println("不是一个 bean = " + clazz); } System.out.println("====================================================="); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } } } }
createBean()方法
public Object createBean(String beanName, BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); Object instance = null; try { instance = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { Object bean = getBean(declaredField.getName()); try { declaredField.setAccessible(true); declaredField.set(instance, bean); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } System.out.println("===============创建好了实例 Set 方法执行完==============="); for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) { Object temp = beanPostProcessor.postProcessBeforeInitialization(instance, beanName); if(temp != null) { instance = temp; } } if(instance instanceof InitializingBean) { try { ((InitializingBean) instance).afterPropertiesSet(); } catch (Exception e) { throw new RuntimeException(e); } } for(BeanPostProcessor beanPostProcessor : beanPostProcessorList) { Object temp = beanPostProcessor.postProcessAfterInitialization(instance, beanName); if(temp != null) { instance = temp; } } return instance; }
结果 :
1. 在component中创建SmartAnimalable, 以它为接口, 我们写类去实现它, 用动态代理实现切面编程
public interface SmartAnimalable { float getSum(float i, float j); float getSub(float i, float j); }
2. 在component中创建SmartDog类去实现SmartAnimalable
@Component("smartDog") public class SmartDog implements SmartAnimalable{ @Override public float getSum(float i, float j) { float result = i + j; System.out.println("getSum() 方法内部打印 result= " + result); return result; } @Override public float getSub(float i, float j) { float result = i - j; System.out.println("getSub() 方法内部打印 result= " + result); return result; } }
3. 在annotation中创建注解Aspect, After, Before
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface After { String value(); }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Before { String value(); }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Aspect { String value() default ""; }
4. 在component中创建SmartAnimalAspect该类就是切面类, 对注解了的类的方法进行切面
@Aspect @Component public class SmartAnimalAspect { @Before("execution com.lxbStu.spring.component.SmartDog getSum") public void showBeginLog() { System.out.println("前置通知"); } @After("execution com.lxbStu.spring.component.SmartDog getSum") public void showSuccessEndLog() { System.out.println("返回通知"); } }
5. 在aop中创建一个工具类, 用于存放aspect对应那个类的那个方法的关系, 为了简化操作将该类的属性和方法设置为静态
public class AspectContainer { private static final ConcurrentHashMapaspectJMap = new ConcurrentHashMap<>(); public static void add(Class clazz, String[] value) { aspectJMap.put(clazz, value); } public static ConcurrentHashMap getAspectJ() { return aspectJMap; } }
6. 修改LxbSpringApplicationContext类中的LoaderResourceByConfig()方法在扫描的时候将切面类的信息封装到AspectContainer中的Map里面, 为了方便之后后置处理器的postProcessAfterInitialization()方法之后执行时直接查找是否某个类可以用到切面类
public void LoaderResourceByConfig(Class ClassConfig) throws RuntimeException { this.config = ClassConfig; ComponentScan component = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class); String path = component.value(); path = path.replace(".", "/"); System.out.println("扫描的路径是 : " + path); ClassLoader classLoader = LxbSpringApplicationContext.class.getClassLoader(); URL resource = classLoader.getResource(path); //System.out.println(resource); File ComponentFile = new File(resource.getFile()); if (ComponentFile.isDirectory()) { File[] files = ComponentFile.listFiles(); for (File file : files) { System.out.println("====================================================="); String classPath = file.getAbsolutePath(); System.out.println("类的绝对路径是 : " + classPath); if (classPath.endsWith(".class")) { String className = classPath.substring(classPath.lastIndexOf("\\") + 1, classPath.indexOf(".class")); String classFullPath = path.replace("/", ".") + "." + className; System.out.println("类的全路径是 :" + classFullPath + ", 类名是 :" + className); try { Class> clazz = Class.forName(classFullPath); if (clazz.isAnnotationPresent(Component.class)) { Component beanId = clazz.getDeclaredAnnotation(Component.class); String id = beanId.value(); if (id == null || "".equals(id)) { id = className.substring(0, 1).toLowerCase() + className.substring(1); } //System.out.println(value); if(clazz.isAnnotationPresent(Aspect.class)) { Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String classAndMethod = null; if(method.getDeclaredAnnotation(Before.class) != null) { Before before = method.getDeclaredAnnotation(Before.class); classAndMethod = before.value(); } if(method.getDeclaredAnnotation(After.class) != null) { After after = method.getDeclaredAnnotation(After.class); classAndMethod = after.value(); } if(classAndMethod != null) { // 我只需要把aspect方法里的注解的信息进行分析就可以了, 至于aspect只需要将它的对象的路径放在字符串数组中即可 String[] split = classAndMethod.split(" "); Class> key = Class.forName(split[1]); String methodName = split[2]; String[] value = new String[] {methodName, classFullPath}; // 封装为 = 类路径 + 方法 AspectContainer.add(key, value); break; } } System.out.println("是一个 AspectJ = " + clazz); continue; } // 这行很重要 if(BeanPostProcessor.class.isAssignableFrom(clazz)) { BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.newInstance(); beanPostProcessorList.add(beanPostProcessor); System.out.println("是一个 BeanPostProcessor = " + clazz); continue; } BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); if (clazz.isAnnotationPresent(Scope.class)) { Scope scope = clazz.getDeclaredAnnotation(Scope.class); beanDefinition.setScope(scope.value()); } else { beanDefinition.setScope("singleton"); } beanDefinitionMap.put(id, beanDefinition); System.out.println("是一个 bean = " + clazz); } else { System.out.println("不是一个 bean = " + clazz); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } } } }
7. 修改component中的LxbBeanPostProcessor类后置处理器中的postProcessAfterInitialization() 方法, 保证在后置处理器的after方法中返回代理对象, 并将执行逻辑进行修改
@Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("postProcessAfterInitialization 被调用 " + beanName + " bean= " + bean.getClass()); ConcurrentHashMapaspectJ = AspectContainer.getAspectJ(); String[] strings = aspectJ.get(bean.getClass()); if(strings != null) { Object proxyInstance = Proxy.newProxyInstance(LxbBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (strings[0].equals(method.getName())) { Class> clazz = Class.forName(strings[1]); Method[] methods = clazz.getDeclaredMethods(); Method before = SpringUtils.FindMethodByName(methods, "showBeginLog"); before.invoke(clazz.newInstance()); result = method.invoke(bean, args); Method after = SpringUtils.FindMethodByName(methods, "showSuccessEndLog"); after.invoke(clazz.newInstance()); } else { result = method.invoke(proxy, args); } return result; } }); return proxyInstance; } return bean; }
8. 测试类
public class SpringTest { @Test public void ConfigTest() { LxbSpringApplicationContext ioc = new LxbSpringApplicationContext(LxbSpringConfig.class); System.out.println("====================================================="); //ConcurrentHashMapbeans = ioc.getIoc(); //Enumeration keys = beans.keys(); //while (keys.hasMoreElements()) { // String id = keys.nextElement(); // System.out.println(beans.get(id)); //} //MonsterService monsterService = (MonsterService) ioc.getBean("monsterService"); //monsterService.m1(); //ConcurrentHashMap aspectJ = AspectContainer.getAspectJ(); //Enumeration keys = aspectJ.keys(); //while(keys.hasMoreElements()) { // Class aClass = keys.nextElement(); // String[] strings = aspectJ.get(aClass); // System.out.println(Arrays.toString(strings)); //} SmartAnimalable bean = (SmartAnimalable) ioc.getBean("smartDog"); float sum = bean.getSum(1, 9); } }
结果 :
最后项目的结是 :