淮南做网站的公司,宁波网站建设公司信息查询,装修公司网站如何做网络推广,ps海报素材网站文章目录 模拟Spring底层详解1、结合配置类#xff0c;扫描类资源1.1、创建需要扫描的配置类AppConfig#xff0c;如下#xff1a;1.2、创建Spring容器对象LyfApplicationContext#xff0c;如下1.3、Spring容器对象LyfApplicationContext扫描资源 2、结合上一步的扫描扫描类资源1.1、创建需要扫描的配置类AppConfig如下1.2、创建Spring容器对象LyfApplicationContext如下1.3、Spring容器对象LyfApplicationContext扫描资源 2、结合上一步的扫描遍历其Map集合创建对象3、创建对象后需要提供需要获取Bean的方法4、总结 模拟Spring底层详解
前置准备创建部分注解具体如下
/*** 依赖注入注解信息*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.FIELD)
public interface Autowired {
}/*** 自定义一个注解是为了标识使用此注解之处的类资源需要交给Spring容器管理* 可自定义beanName*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
public interface Component {String value() default ;
}/*** 定于扫描类bean资源路径*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
public interface ComponentScan {String value() default ;
}Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
public interface Scope {String value() default ;
}
两个service类用于测试
Component
Scope()
public class OrderService {
}Component
public class UserService {private String name;Autowiredprivate OrderService orderService;public void testDemo(){System.out.println(Spring 创建 userService 实例成功);System.out.println(Spring 依赖注入 orderService 实例对象orderService);}
}一个测试类
public class TestSpringDemo {public static void main(String[] args) throws Exception{LyfApplicationContext context new LyfApplicationContext(AppConfig.class);UserService userService (UserService) context.getBean(userService);userService.testDemo();}
}1、结合配置类扫描类资源
Spring在创建对象前需要去扫描确定需要交给Spring管理的类资源具体的实现步骤模拟代码如下
1.1、创建需要扫描的配置类AppConfig如下 /*** 这个类主要是用于定义扫描资源的路径信息*/
ComponentScan(com.practice.service)
public class AppConfig {
}1.2、创建Spring容器对象LyfApplicationContext如下
/*** 这个类主要是用于模拟Spring容器的bean的创建与获取bean等*/
public class LyfApplicationContext {public LyfApplicationContext(Class config) throws Exception{}}1.3、Spring容器对象LyfApplicationContext扫描资源
在LyfApplicationContext容器含参构造中需要结合传入扫描资源的配置类AppConfig对资源进行扫描具体实现代码如下
/*** 这个类主要是用于模拟Spring容器的bean的创建与获取bean等*/
public class LyfApplicationContext {public LyfApplicationContext(Class config) throws Exception{//判断传入的config类上是否有componentScan注解if (config.isAnnotationPresent(ComponentScan.class)) {//1、获取传入类上的注解ComponentScan信息主要是获取扫描路径ComponentScan componentScanAnnotation (ComponentScan) config.getAnnotation(ComponentScan.class);//2、获取注解中的值String path componentScanAnnotation.value();//3、将注解中的值.换为/path path.replace(.,/);//4、结合当前容器的类加载器加载路径path下的class资源//4.1 先获取当前容器的类加载器ClassLoader classLoader LyfApplicationContext.class.getClassLoader();//4.2 利用上一步获取的类加载器获取path路径下的class文件资源url信息URL resource classLoader.getResource(path); //D:/JavaWorkSpace/2023/spring/spring-study-demo01/target/classes/com/practice/service//4.3 获取当前resource路径下的文件资源信息File file new File(resource.getFile());//4.4 遍历file文件数据获取file下的所有class文件资源if (file.isDirectory()) {for (File f : file.listFiles()) {String absolutePath f.getAbsolutePath(); //获取到class资源的绝对路径信息目的是为了加载此类信息// 4.4.1 将此类的绝对路径做处理截取一部分absolutePath absolutePath.substring(absolutePath.indexOf(com),absolutePath.indexOf(.class)).replace(\\,.);//com.practice.service.UserService//4.4.2 用上述得到的类加载器加载上述的absolutePath路径下的class资源信息目的是为了检查当前遍历的class资源上是否包含Component注解try{Class? clazz classLoader.loadClass(absolutePath);// 如果当前的对象实现了beanPostProcessor接口需要将其加入beanPostProcessorList集合中if (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor instance (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}if (clazz.isAnnotationPresent(Component.class)) {//创建一个BeanDefinition对象用于保存每个类的特征BeanDefinition beanDefinition new BeanDefinition();beanDefinition.setType(clazz);//4.4.2.1 获取当前注解Component的值之定义的beanNameComponent annotation clazz.getAnnotation(Component.class);String beanName annotation.value();//如果当前传入的beanName为空的话利用默认的也就是类名首字母小写作为beanNameif (.equals(beanName)) {beanName Introspector.decapitalize(clazz.getSimpleName());}//4.4.2.2 除此之外还需要判断是否有Scope注解主要是判断当前的bean是否是单例或者是原型的if (clazz.isAnnotationPresent(Scope.class)) {//获取注解中的值Scope scopeAnnotation clazz.getAnnotation(Scope.class);String value scopeAnnotation.value();beanDefinition.setScope(value);}else {beanDefinition.setScope(singleton);}//将封装好的beanDefinition缓存到Map中beanDefinitionMap.put(beanName,beanDefinition);}}catch (Exception e){throw new Exception(absolutePath 类加载失败,e);}}}}else {throw new Exception(缺少路径资源配置信息~~~);}}
}其过程如下 先结合传入扫描资源的配置类AppConfig类上是否包含注解ComponentScan若包含注解需要获取其注解中的参数信息配置的扫描包路径获取当前资源的类加载器目的是为了获取target包下的class资源信息获取到指定包路径下的class资源利用其构造方法创建对象对对象中的属性以及对象上加入的注解信息进行遍历扫描进行相关的逻辑处理将其类元信息加入到BeanDefinition对象中再将其封装为一个Map对象在接下来的对象创建与获取的过程中做好基奠其对象信息就是记录每一个类的特征部分代码如下 /*** 这个类主要是去记录下描述一个bean的特征*/
public class BeanDefinition {//类的类型private Class type;//创建类的方式单例还是原型等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) {this.scope scope;}
}2、结合上一步的扫描遍历其Map集合创建对象
/*** 这个类主要是用于模拟Spring容器的bean的创建与获取bean等*/
public class LyfApplicationContext {public LyfApplicationContext(Class config) throws Exception{//判断传入的config类上是否有componentScan注解if (config.isAnnotationPresent(ComponentScan.class)) {//1、获取传入类上的注解ComponentScan信息主要是获取扫描路径ComponentScan componentScanAnnotation (ComponentScan) config.getAnnotation(ComponentScan.class);//2、获取注解中的值String path componentScanAnnotation.value();//3、将注解中的值.换为/path path.replace(.,/);//4、结合当前容器的类加载器加载路径path下的class资源//4.1 先获取当前容器的类加载器ClassLoader classLoader LyfApplicationContext.class.getClassLoader();//4.2 利用上一步获取的类加载器获取path路径下的class文件资源url信息URL resource classLoader.getResource(path); //D:/JavaWorkSpace/2023/spring/spring-study-demo01/target/classes/com/practice/service//4.3 获取当前resource路径下的文件资源信息File file new File(resource.getFile());//4.4 遍历file文件数据获取file下的所有class文件资源if (file.isDirectory()) {for (File f : file.listFiles()) {String absolutePath f.getAbsolutePath(); //获取到class资源的绝对路径信息目的是为了加载此类信息// 4.4.1 将此类的绝对路径做处理截取一部分absolutePath absolutePath.substring(absolutePath.indexOf(com),absolutePath.indexOf(.class)).replace(\\,.);//com.practice.service.UserService//4.4.2 用上述得到的类加载器加载上述的absolutePath路径下的class资源信息目的是为了检查当前遍历的class资源上是否包含Component注解try{Class? clazz classLoader.loadClass(absolutePath);// 如果当前的对象实现了beanPostProcessor接口需要将其加入beanPostProcessorList集合中if (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor instance (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}if (clazz.isAnnotationPresent(Component.class)) {//创建一个BeanDefinition对象用于保存每个类的特征BeanDefinition beanDefinition new BeanDefinition();beanDefinition.setType(clazz);//4.4.2.1 获取当前注解Component的值之定义的beanNameComponent annotation clazz.getAnnotation(Component.class);String beanName annotation.value();//如果当前传入的beanName为空的话利用默认的也就是类名首字母小写作为beanNameif (.equals(beanName)) {beanName Introspector.decapitalize(clazz.getSimpleName());}//4.4.2.2 除此之外还需要判断是否有Scope注解主要是判断当前的bean是否是单例或者是原型的if (clazz.isAnnotationPresent(Scope.class)) {//获取注解中的值Scope scopeAnnotation clazz.getAnnotation(Scope.class);String value scopeAnnotation.value();beanDefinition.setScope(value);}else {beanDefinition.setScope(singleton);}//将封装好的beanDefinition缓存到Map中beanDefinitionMap.put(beanName,beanDefinition);}}catch (Exception e){throw new Exception(absolutePath 类加载失败,e);}}}}else {throw new Exception(缺少路径资源配置信息~~~);}}//创建对象for (Map.EntryString, BeanDefinition definitionEntry : beanDefinitionMap.entrySet()) {//获取BeanDefinitionMap中的key和valueString beanName definitionEntry.getKey();BeanDefinition definition definitionEntry.getValue();//判断当前的BeanDefinition对象是否是单例if (singleton.equals(definition.getScope())) {Object bean creatBean(beanName, definition);singletonMap.put(beanName,bean);}}/*** 创建bean对象* param beanName bean名称* param definition 对象描述封装类* return* throws Exception*/public Object creatBean(String beanName, BeanDefinition definition) throws Exception {//创建当前对象且放入单例池中单例的Map中Class clazz definition.getType();try {Object instance clazz.getConstructor().newInstance();//判断当前的对象中是否有autowide依赖注入注解 ,如果包含这个注解需要将其字段进行赋值for (Field field : clazz.getDeclaredFields()) {if (field.isAnnotationPresent(Autowired.class)) {field.setAccessible(true);field.set(instance, getBean(field.getName()));}}//回到方法beanNameAwareif (instance instanceof BeanNameAware) {((BeanNameAware) instance).setBeanName(beanName);}//初始化前方法if (beanPostProcessorList.size() 0) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}}//初始化if (instance instanceof InitializingBean) {((InitializingBean) instance).afterPropertiesSet();}//初始化后切面AOPif (beanPostProcessorList.size() 0) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance beanPostProcessor.postProcessAfterInitialization(instance, beanName);}}return instance;} catch (Exception e){throw new Exception(创建对象失败~~~,e);}}
}
3、创建对象后需要提供需要获取Bean的方法
/*** 定于一个方法是获取bean资源的*/public Object getBean(String beanName) throws Exception {//判断当前的BeanDefinitionMap中是否存在beanName为key的beanDefinitionif (!beanDefinitionMap.containsKey(beanName)) {throw new Exception(当前beanName在BeanDefinitionMap中不存在~~~);}//从BeanDefinitionMap中获取到BeanDefinition信息判断其scopeBeanDefinition beanDefinition beanDefinitionMap.get(beanName);//单例if (singleton.equals(beanDefinition.getScope())) {Object singletonBean singletonMap.get(beanName);if (singletonBean null) {singletonBean creatBean(beanName,beanDefinition);singletonMap.put(beanName,singletonBean);}return singletonBean;}else {//原型Object prototypeBean creatBean(beanName,beanDefinition);return prototypeBean;}}4、总结
总的来说在Spring创建对象的过程中主要分为结合传入的类路径信息扫描需要创建的对象资源结合上一步的扫描结果创建对象将创建好的对象提供一个对外获取Bean接口具体详细过程图示