手写Spring3.x以上
一.准备工作
1.创建maven项目
2.创建配置类,加载容器类,启动类
public class CharkeyApplicationContext { private Class appConfig; public CharkeyApplicationContext(Class appConfig) { this.appConfig = appConfig; } public Object getBean(String name) { return null; } }
public class Application { public static void main(String[] args) { CharkeyApplicationContext chakeyApplicationContext = new CharkeyApplicationContext(AppConfig.class); Object bean1 = chakeyApplicationContext.getBean("userService"); System.out.println(bean1); } }
二.IOC之扫描加载Bean对象
1.添加扫描Config类注解compentScan
2.添加compent注解标注扫描类
3.Bean加载到容器中
4.调用getBean
package annotiton; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Component { String value() default ""; }
package annotiton; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ComponentScan { String value(); }
package annotiton; public class BeanDefinition { private Class clazz; private String scope;//单例 多例 public BeanDefinition() { } public BeanDefinition(Class clazz, String scope) { this.clazz = clazz; this.scope = scope; } public Class getClazz() { return clazz; } public void setClazz(Class clazz) { this.clazz = clazz; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } }
@Component("orderService") public class OrderServiceImpl implements OrderService { }
@Component("userService") public class UserServiceImpl implements UserService { }
package config; import annotiton.ComponentScan; @ComponentScan("service.impl") public class AppConfig { }
package spring; import annotiton.BeanDefinition; import annotiton.Component; import annotiton.ComponentScan; import java.io.File; import java.net.URL; import java.util.concurrent.ConcurrentHashMap; public class CharkeyApplicationContext { private Class appConfig; private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>(); public CharkeyApplicationContext(Class configClass) { this.appConfig = appConfig; //扫描bean scan(configClass); } public Object getBean(String name) { BeanDefinition beanDefinition = beanDifinitionMap.get(name); return beanDefinition; } public void scan(Class app) { boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class); if (!annotationPresent) throw new RuntimeException("没有配置类"); ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class); String path = componentScan.value(); System.out.println(path); ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader(); path = path.replace(".", "/"); System.out.println(path); URL resource = classLoader.getResource("service/impl");//"com/charkey/service" File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { File file1 = files[i]; String absolutePath = file1.getAbsolutePath(); System.out.println(absolutePath); absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class")); System.out.println(absolutePath); absolutePath = absolutePath.replace("\\", "."); System.out.println(absolutePath); Class<?> clazz = null; try { clazz = classLoader.loadClass(absolutePath); boolean isComponent = clazz.isAnnotationPresent(Component.class); if (!isComponent) continue; Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class); String beanName = declaredAnnotation.value(); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); beanDifinitionMap.put(beanName, beanDefinition); } catch (ClassNotFoundException e) { e.printStackTrace(); } if (clazz != null && clazz.isAnnotationPresent(Component.class)) { System.out.println(absolutePath); } } } } }
三.Scope注解实现可配置的单例,多例对象
1.添加Scope注解,默认为singleton
2.被Compoent注解扫描的类被scope注解定义为Prototype视为多例,否则为单例
3.Bean加载到容器中
4.单例时从bean容器中取出,多例时创建新对象
package annotiton; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Scope { String value() default "singleton"; }
package spring; import annotiton.BeanDefinition; import annotiton.Component; import annotiton.ComponentScan; import annotiton.Scope; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.concurrent.ConcurrentHashMap; public class CharkeyApplicationContext { private Class appConfig; private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>(); public CharkeyApplicationContext(Class configClass) { this.appConfig = appConfig; //扫描bean scan(configClass); } public Object getBean(String name) { BeanDefinition beanDefinition = beanDifinitionMap.get(name); String scope = beanDefinition.getScope(); if(scope.equals("prototype"))return createBean(name, beanDefinition); return beanDefinition; } public Object createBean(String beanName, BeanDefinition beanDefinition) { Object object = null; try { Class clazz = beanDefinition.getClazz(); object = clazz.getDeclaredConstructor().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return object; } public void scan(Class app) { boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class); if (!annotationPresent) throw new RuntimeException("没有配置类"); ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class); String path = componentScan.value(); System.out.println(path); ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader(); path = path.replace(".", "/"); System.out.println(path); URL resource = classLoader.getResource("service/impl");//"com/charkey/service" File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { File file1 = files[i]; String absolutePath = file1.getAbsolutePath(); System.out.println(absolutePath); absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class")); System.out.println(absolutePath); absolutePath = absolutePath.replace("\\", "."); System.out.println(absolutePath); Class<?> clazz = null; try { clazz = classLoader.loadClass(absolutePath); boolean isComponent = clazz.isAnnotationPresent(Component.class); if (!isComponent) continue; Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class); String beanName = declaredAnnotation.value(); String scopeVal = "singleton";//默认单例Bean boolean isScope = clazz.isAnnotationPresent(Scope.class); if(isScope){ Scope scope1 = clazz.getDeclaredAnnotation(Scope.class); scopeVal = scope1.value(); } BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); beanDefinition.setScope(scopeVal); beanDifinitionMap.put(beanName, beanDefinition); } catch (ClassNotFoundException e) { e.printStackTrace(); } if (clazz != null && clazz.isAnnotationPresent(Component.class)) { System.out.println(absolutePath); } } } } }
四.使用Autowired控制反转以及依赖注入
1.添加Autowired注解,增加requied属性
2.模拟DI创建bean容器
3.在创建bean时,把bean中的被autowired定义的属性加载
package annotiton; import java.lang.annotation.*; @Target({ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean value() default true; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | package spring; import annotiton.*; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.concurrent.ConcurrentHashMap; public class CharkeyApplicationContext { private Class appConfig; private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>(); public CharkeyApplicationContext(Class configClass) { this .appConfig = appConfig; //扫描bean scan(configClass); beanDifinitionMap.forEach((beanName, clazz) -> { String scope = clazz.getScope(); if (scope.equals( "singleton" )) { Object bean = createBean(beanName, clazz); singletonObjects.put(beanName, bean); } }); } public Object getBean(String name) { BeanDefinition beanDefinition = beanDifinitionMap.get(name); String scope = beanDefinition.getScope(); if (scope.equals( "prototype" )) return createBean(name, beanDefinition); return singletonObjects.get(name); } public Object createBean(String beanName, BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); try { Object o = clazz.getDeclaredConstructor().newInstance(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { boolean annotationPresent = field.isAnnotationPresent(Autowired. class ); if (annotationPresent) { Autowired autowired = (Autowired) clazz.getDeclaredAnnotation(Autowired. class ); boolean requied = autowired.value(); if (requied && o == null ) throw new RuntimeException( "没有找到bean" ); Object bean = getBean(field.getName()); field.setAccessible( true ); field.set(o, bean); } } return o; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null ; } public void scan(Class app) { boolean annotationPresent = app.isAnnotationPresent(ComponentScan. class ); if (!annotationPresent) throw new RuntimeException( "没有配置类" ); ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan. class ); String path = componentScan.value(); System.out.println(path); ClassLoader classLoader = CharkeyApplicationContext. class .getClassLoader(); path = path.replace( "." , "/" ); System.out.println(path); URL resource = classLoader.getResource( "service/impl" ); //"com/charkey/service" File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for ( int i = 0 ; i < files.length; i++) { File file1 = files[i]; String absolutePath = file1.getAbsolutePath(); System.out.println(absolutePath); absolutePath = absolutePath.substring(absolutePath.indexOf( "service" ), absolutePath.indexOf( ".class" )); System.out.println(absolutePath); absolutePath = absolutePath.replace( "\\" , "." ); System.out.println(absolutePath); Class<?> clazz = null ; try { clazz = classLoader.loadClass(absolutePath); boolean isComponent = clazz.isAnnotationPresent(Component. class ); if (!isComponent) continue ; Component declaredAnnotation = clazz.getDeclaredAnnotation(Component. class ); String beanName = declaredAnnotation.value(); String scopeVal = "singleton" ; //默认单例Bean boolean isScope = clazz.isAnnotationPresent(Scope. class ); if (isScope){ Scope scope1 = clazz.getDeclaredAnnotation(Scope. class ); scopeVal = scope1.value(); } BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); beanDefinition.setScope(scopeVal); beanDifinitionMap.put(beanName, beanDefinition); } catch (ClassNotFoundException e) { e.printStackTrace(); } if (clazz != null && clazz.isAnnotationPresent(Component. class )) { System.out.println(absolutePath); } } } } } |
五. Bean的生命周期
1.创建InitializingBean接口,定义初始化方法
2.修饰到需要初始化的Compent类上
3.创建Bean时,触发初始化方法
package annotiton; public interface InitializingBean { void afterPropertiesSet() throws Exception; }
package service.impl; import annotiton.Autowired; import annotiton.Component; import annotiton.InitializingBean; import annotiton.Scope; import service.OrderService; import service.UserService; @Component("userService") @Scope("prototype") public class UserServiceImpl implements UserService, InitializingBean { @Autowired private OrderService orderService; private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void testAutowired(){ System.out.println(orderService); } @Override public void afterPropertiesSet() throws Exception { System.out.println("bean初始化。。。"); //System.out.println(getName()); } }
六. 监听Bean的初始化前、初始化、初始化后
1.Bean生命周期接口及实现 BeanPostProcessor 和 MyBeanPostInitialization,并在MyBeanPostInitialization添加Compent
2.扫描时将BeanPostProcessor 放到容器中
3.创建Bean时,从容器中取出BeanPostProcessor ,并执行初始化方法
package annotiton; public interface BeanPostProcessor { Object postProcessorBeforeInintion(String beanName, Object bean); Object postProcessorAfterInintion(String beanName, Object bean); }
package service.impl; import annotiton.BeanPostProcessor; import annotiton.Component; import service.OrderService; @Component public class MyBeanPostInitialization implements BeanPostProcessor { @Override public Object postProcessorBeforeInintion(String beanName, Object bean) { if (beanName.equals("orderService")) { OrderService orderService = (OrderService) bean; System.out.println("Bean开始初始化。。。"); orderService.setName("charkey"); } return bean; } @Override public Object postProcessorAfterInintion(String beanName, Object bean) { if (beanName.equals("orderService")) { OrderService orderService = (OrderService) bean; System.out.println("Bean初始化结束。。。name为。。。" + orderService.getName()); } return bean; } }
扫描
package spring; import annotiton.*; 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; public class CharkeyApplicationContext { private Class appConfig; private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>(); private static List<BeanPostProcessor> listBean = new ArrayList<>(); public CharkeyApplicationContext(Class configClass) { this.appConfig = appConfig; //扫描bean scan(configClass); beanDifinitionMap.forEach((beanName, clazz) -> { String scope = clazz.getScope(); if (scope.equals("singleton")) { Object bean = createBean(beanName, clazz); singletonObjects.put(beanName, bean); } }); } public Object getBean(String name) { BeanDefinition beanDefinition = beanDifinitionMap.get(name); String scope = beanDefinition.getScope(); if (scope.equals("prototype")) return createBean(name, beanDefinition); return singletonObjects.get(name); } public Object createBean(String beanName, BeanDefinition beanDefinition) { Class clazz = beanDefinition.getClazz(); try { Object o = clazz.getDeclaredConstructor().newInstance(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { boolean annotationPresent = field.isAnnotationPresent(Autowired.class); if (annotationPresent) { Autowired autowired = (Autowired) clazz.getDeclaredAnnotation(Autowired.class); if (autowired == null) continue; boolean requied = autowired.value(); if (requied && o == null) throw new RuntimeException("没有找到bean"); Object bean = getBean(field.getName()); field.setAccessible(true); field.set(o, bean); } } //初始化前执行 for (BeanPostProcessor processor : listBean) { processor.postProcessorBeforeInintion(beanName,o); } //初始化执行 if (o instanceof InitializingBean) { ((InitializingBean) o).afterPropertiesSet(); } //初始化前执行 for (BeanPostProcessor processor : listBean) { processor.postProcessorAfterInintion(beanName,o); } return o; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } public void scan(Class app) { boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class); if (!annotationPresent) throw new RuntimeException("没有配置类"); ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class); String path = componentScan.value(); System.out.println(path); ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader(); path = path.replace(".", "/"); System.out.println(path); URL resource = classLoader.getResource("service/impl");//"com/charkey/service" File file = new File(resource.getFile()); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { File file1 = files[i]; String absolutePath = file1.getAbsolutePath(); System.out.println(absolutePath); absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class")); System.out.println(absolutePath); absolutePath = absolutePath.replace("\\", "."); System.out.println(absolutePath); Class<?> clazz = null; try { clazz = classLoader.loadClass(absolutePath); boolean isComponent = clazz.isAnnotationPresent(Component.class); if (!isComponent) continue; Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class); String beanName = declaredAnnotation.value(); if (BeanPostProcessor.class.isAssignableFrom(clazz)) {//MyBeanPostInitialization BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance(); listBean.add(beanPostProcessor); } if((clazz.getName()).indexOf("MyBeanPostInitialization") > 0)continue; if((beanName == null || beanName.equals("")) ){ beanName = clazz.getName().substring(clazz.getName().lastIndexOf(".")+1); beanName = Character.toLowerCase(beanName.charAt(0)) + (beanName.length() > 1 ? beanName.substring(1) :""); beanName = beanName.replace("Impl",""); } String scopeVal = "singleton";//默认单例Bean boolean isScope = clazz.isAnnotationPresent(Scope.class); if (isScope) { Scope scope1 = clazz.getDeclaredAnnotation(Scope.class); scopeVal = scope1.value(); } BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClazz(clazz); beanDefinition.setScope(scopeVal); beanDifinitionMap.put(beanName, beanDefinition); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } if (clazz != null && clazz.isAnnotationPresent(Component.class)) { System.out.println(absolutePath); } } } } }
五.实现AOP
在Bean初始化完成后,配置JDK的Proxy对象并返回
package service.impl; import annotiton.BeanPostProcessor; import annotiton.Component; import service.OrderService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @Component public class MyBeanPostInitialization implements BeanPostProcessor { @Override public Object postProcessorBeforeInintion(String beanName, Object bean) { if (beanName.equals("orderService")) { OrderService orderService = (OrderService) bean; System.out.println("Bean开始初始化。。。"); orderService.setName("charkey"); } return bean; } @Override public Object postProcessorAfterInintion(String beanName, Object bean) { if (beanName.equals("orderService")) { OrderService orderService = (OrderService) bean; System.out.println("Bean初始化结束。。。name为。。。" + orderService.getName()); Object proxyInstance = Proxy.newProxyInstance(MyBeanPostInitialization.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行test方法前AOP执行逻辑。。。。。"); return method.invoke(bean, args); } }); return proxyInstance; } return bean; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?