网站建设哪里找广州市数商云网络科技有限公司

web/2025/10/2 14:00:18/文章来源:
网站建设哪里找,广州市数商云网络科技有限公司,wordpress怎么进登录界面,深圳网站建设网站制作哪家好文章目录 ⭐⭐⭐Spring核心源码分析自定义Spring框架⭐⭐⭐一、Spring使用回顾二、Spring核心功能结构1、Spring核心功能2、bean概述 三、Spring IOC相关接口分析1、BeanFactory解析2、BeanDefinition解析3、BeanDefinitionReader解析4、BeanDefinitionRegistry解析5、创建容器… 文章目录 ⭐⭐⭐Spring核心源码分析自定义Spring框架⭐⭐⭐一、Spring使用回顾二、Spring核心功能结构1、Spring核心功能2、bean概述 三、Spring IOC相关接口分析1、BeanFactory解析2、BeanDefinition解析3、BeanDefinitionReader解析4、BeanDefinitionRegistry解析5、创建容器 四、自定义SpringIOC1、定义bean相关的pojo类1PropertyValue类2MutablePropertyValues类3BeanDefinition类 2、定义注册表相关类1BeanDefinitionRegistry接口2SimpleBeanDefinitionRegistry类 3、定义解析器相关类1BeanDefinitionReader接口2XmlBeanDefinitionReader类 4、IOC容器相关类1BeanFactory接口2ApplicationContext接口3AbstractApplicationContext类4ClassPathXmlApplicationContext类 5、测试运行自定义Spring IOC框架6、自定义Spring IOC总结1使用到的设计模式2符合大部分设计原则3整个设计和Spring的设计还是有一定的出入 五、设计模式常见相关面试问题 ⭐⭐⭐Spring核心源码分析自定义Spring框架⭐⭐⭐ 学习完这个篇章以后【23种设计模式·全精解析】至此完结。相信手写完这个自定义Spring框架后你可以对Spring的核心底层有更深的认识并学会设计模式在具体实际开发中的如何去灵活应用 一、Spring使用回顾 自定义spring框架前先回顾一下spring框架的使用从而分析spring的核心并对核心功能进行模拟。 数据访问层。定义UserDao接口及其子实现类 // 数据访问层接口 public interface UserDao {void add(); }// 数据访问层实现类 public class UserDaoImpl implements UserDao {Overridepublic void add() {System.out.println(UserDao...);} }业务逻辑层。定义UserService接口及其子实现类 // 业务逻辑层接口 public interface UserService {void add(); }// 业务逻辑层实现类 public class UserServiceImpl implements UserService {// 声明一个UserDao类型的变量private UserDao userDao;// 通过Spring依赖注入进行赋值public void setUserDao(UserDao userDao) {this.userDao userDao;}Overridepublic void add() {System.out.println(UserService...);userDao.add();} }定义UserController类使用main方法模拟controller层 import com.aizen.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;// 控制层 public class UserController {public static void main(String[] args) {// 创建Spring的容器对象非延时加载ApplicationContext applicationContext new ClassPathXmlApplicationContext(applicationContext.xml);// 从ioc容器对象中获取userService对象UserService userService applicationContext.getBean(userService, UserService.class);//调用userService方法进行业务逻辑处理userService.add();} }编写配置文件。在类路径下编写一个名为applicationContext.xml的配置文件 ?xml version1.0 encodingUTF-8? beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean iduserDao classcom.aizen.dao.impl.UserDaoImpl/!-- IOC容器管理对象 --bean iduserService classcom.aizen.service.impl.UserServiceImplproperty nameuserDao refuserDao/!-- 依赖注入DI --/bean /beans代码运行结果如下 通过上面代码及结果可以看出 userService对象是从applicationContext容器对象获取到的也就是userService对象交由spring进行管理。上面结果可以看到调用了UserDao对象中的add方法也就是说UserDao子实现类对象也交由spring管理了。UserService中的userDao变量我们并没有进行赋值但是可以正常使用说明spring已经将UserDao对象赋值给了userDao变量。 上面三点体现了Spring框架的IOCInversion of Control和DIDependency Injection, DI 二、Spring核心功能结构 1、Spring核心功能 Spring大约有20个模块由1300多个不同的文件构成。这些模块可以分为核心容器、AOP和设备支持、数据访问与集成、Web组件、通信报文和集成测试等下面是 Spring 框架的总体架构图 核心容器由 beans、core、context 和 expressionSpring Expression LanguageSpEL4个模块组成。 spring-beans和spring-core模块是Spring框架的核心模块包含了控制反转Inversion of ControlIOC和依赖注入Dependency InjectionDI。BeanFactory使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。BeanFactory属于延时加载也就是说在实例化容器对象后并不会自动实例化Bean只有当Bean被使用时BeanFactory才会对该 Bean 进行实例化与依赖关系的装配。 // 延时加载示例 BeanFactory beanFactory new XmlBeanFactory(new ClassPathResource(applicationContext.xml)); // 执行完getBean方法ioc容器才会创建service和dao对象并绑定依赖关系 UserService userService beanFactory.getBean(userService, UserService.class); userService.add();spring-context模块构架于核心模块之上扩展了BeanFactory为它添加了Bean生命周期控制、框架事件体系及资源加载透明化等功能。此外该模块还提供了许多企业级支持如邮件访问、远程访问、任务调度等ApplicationContext 是该模块的核心接口它的超类是 BeanFactory。与BeanFactory不同ApplicationContext实例化后会自动对所有的单实例Bean进行实例化与依赖关系的装配使之处于待用状态。spring-context-support模块是对Spring IoC容器及IoC子容器的扩展支持。spring-context-indexer模块是Spring的类管理组件和Classpath扫描组件。spring-expression 模块是统一表达式语言EL的扩展模块可以查询、管理运行中的对象同时也可以方便地调用对象方法以及操作数组、集合等。它的语法类似于传统EL但提供了额外的功能最出色的要数函数调用和简单字符串的模板函数。EL的特性是基于Spring产品的需求而设计的可以非常方便地同Spring IoC进行交互。 2、bean概述 Spring 就是面向 Bean 的编程BOP ,Bean Oriented ProgrammingBean 在 Spring 中处于核心地位。Bean对于Spring的意义就像Object对于OOP的意义一样Spring中没有Bean也就没有Spring存在的意义。Spring IoC容器通过配置文件或者注解的方式来管理bean对象之间的依赖关系。 spring中bean用于对一个类进行封装。如下面的配置 bean iduserDao classcom.itheima.dao.impl.UserDaoImpl/bean bean iduserService classcom.itheima.service.impl.UserServiceImplproperty nameuserDao refuserDao/property /bean为什么Bean如此重要呢 spring将bean对象交由一个叫IOC容器进行管理。bean对象之间的依赖关系在配置文件中体现并由spring完成。 三、Spring IOC相关接口分析 1、BeanFactory解析 Spring中Bean的创建是典型的工厂模式这一系列的Bean工厂即IoC容器为开发者管理对象之间的依赖关系提供了很多便利和基础服务在Spring中有许多IoC容器的实现供用户选择其相互关系如下图所示。 其中BeanFactory作为最顶层的一个接口定义了IoC容器的基本功能规范BeanFactory有三个重要的子接口ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory它实现了所有的接口。 那么为何要定义这么多层次的接口呢每个接口都有它的使用场合主要是为了区分在Spring内部操作过程中对象的传递和转化对对象的数据访问所做的限制。例如 ListableBeanFactory接口表示这些Bean可列表化。HierarchicalBeanFactory表示这些Bean是有继承关系的也就是每个Bean可能有父BeanAutowireCapableBeanFactory接口定义Bean的自动装配规则。 这三个接口共同定义了Bean的集合、Bean之间的关系及Bean行为。最基本的IoC容器接口是BeanFactory来看一下它的源码 public interface BeanFactory {String FACTORY_BEAN_PREFIX ;// 根据bean的名称获取IOC容器中的的bean对象Object getBean(String name) throws BeansException;// 根据bean的名称获取IOC容器中的的bean对象并指定获取到的bean对象的类型这样我们使用时就不需要进行类型强转了T T getBean(String name, ClassT requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;T T getBean(ClassT requiredType) throws BeansException;T T getBean(ClassT requiredType, Object... args) throws BeansException;T ObjectProviderT getBeanProvider(ClassT requiredType);T ObjectProviderT getBeanProvider(ResolvableType requiredType);// 判断容器中是否包含指定名称的bean对象boolean containsBean(String name);// 根据bean的名称判断是否是单例boolean isSingleton(String name) throws NoSuchBeanDefinitionException;boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, Class? typeToMatch) throws NoSuchBeanDefinitionException;NullableClass? getType(String name) throws NoSuchBeanDefinitionException;String[] getAliases(String name); }在BeanFactory里只对IoC容器的基本行为做了定义根本不关心Bean是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品不关心工厂是怎么生产这些产品的。具体如何创建交给该接口的具体子实现类去实现。 BeanFactory有一个很重要的子接口就是ApplicationContext接口该接口主要来规范容器中的bean对象是非延时加载即在创建容器对象的时候就对象bean进行初始化并存储到一个容器中。 要知道工厂是如何产生对象的我们需要看具体的IoC容器实现Spring提供了许多IoC容器实现比如 ClasspathXmlApplicationContext : 根据类路径加载xml配置文件并创建IOC容器对象。FileSystemXmlApplicationContext 根据系统路径加载xml配置文件并创建IOC容器对象。AnnotationConfigApplicationContext 加载注解类配置并创建IOC容器。 2、BeanDefinition解析 Spring IoC容器管理我们定义的各种Bean对象及其相互关系而Bean对象在Spring实现中是以BeanDefinition来描述的如下面配置文件 bean iduserDao classcom.itheima.dao.impl.UserDaoImpl/beanbean标签还有很多属性scope、init-method、destory-method等。Spring要解析这些bean标签必然要把这些bean标签对应属性的值进行一个封装而封装成的对象就是BeanDefinition对象而BeanDefinition是一个接口所以Spring封装的是BeanDefinition的子实现类对象。 其继承体系如下图所示 3、BeanDefinitionReader解析 Bean的解析过程非常复杂功能被分得很细因为这里需要被扩展的地方很多必须保证足够的灵活性以应对可能的变化。Bean的解析主要就是对Spring配置文件的解析。这个解析过程主要通过BeanDefinitionReader来完成看看Spring中BeanDefinitionReader的类结构图部分如下图所示。 看看BeanDefinitionReader接口定义的功能来理解它具体的作用 public interface BeanDefinitionReader {// 获取BeanDefinitionRegistry注册器对象BeanDefinitionRegistry getRegistry();NullableResourceLoader getResourceLoader();NullableClassLoader getBeanClassLoader();BeanNameGenerator getBeanNameGenerator();/*下面的loadBeanDefinitions都是加载bean定义从指定的资源中获取如String类型的字符冲路径Resource对象类型*/int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException; }4、BeanDefinitionRegistry解析 BeanDefinitionReader用来解析bean定义并封装BeanDefinition对象而我们定义的配置文件中定义了很多bean标签所以就有一个问题解析的多个BeanDefinition对象存储到哪儿答案就是BeanDefinition的注册中心而该注册中心顶层接口就是BeanDefinitionRegistry。 public interface BeanDefinitionRegistry extends AliasRegistry {// 往注册表中注册beanvoid registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;// 从注册表中删除指定名称的beanvoid removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 获取注册表中指定名称的beanBeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 判断注册表中是否已经注册了指定名称的beanboolean containsBeanDefinition(String beanName);// 获取注册表中所有的bean的名称String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String beanName); }继承结构图如下部分 从上面类图可以看到BeanDefinitionRegistry接口的子实现类主要有以下几个 DefaultListableBeanFactory在该类中定义了如下代码就是用来注册beanMapString, BeanDefinition键是BeanDefinition的名称值是BeanDefinition对象 private final MapString, BeanDefinition beanDefinitionMap new ConcurrentHashMap(256);SimpleBeanDefinitionRegistry在该类中定义了如下代码就是用来注册beanMapString, BeanDefinition键是BeanDefinition的名称值是BeanDefinition对象 private final MapString, BeanDefinition beanDefinitionMap new ConcurrentHashMap(64);5、创建容器 ClassPathXmlApplicationContextApplicationContext接口下的子实现类对Bean配置资源的载入非延迟加载是从refresh()方法开始的。 通过查看ClassPathXmlApplicationContext的源码找到refresh()方法。 refresh()方法是一个模板方法规定了 IoC 容器的启动流程有些逻辑要交给其子类实现。 它对 Bean 配置资源进行载入ClassPathXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()方法启动整个IoC容器对Bean定义的载入过程。 简单来说refresh()的功能启动IoC容器加载配置文件并初始化Bean对象将Bean对象存储在容器里面。 四、自定义SpringIOC 现要对下面的配置文件进行解析并自定义Spring框架的IOC对涉及到的对象进行管理。 ?xml version1.0 encodingUTF-8? beansbean iduserService classcom.itheima.service.impl.UserServiceImplproperty nameuserDao refuserDao/property/beanbean iduserDao classcom.itheima.dao.impl.UserDaoImpl/bean /beans总体项目文件及包结构设计 1、定义bean相关的pojo类 1PropertyValue类 用于封装bean的属性体现到上面的配置文件就是封装bean标签的子标签property标签数据。 // 用来封装bean标签下的property标签的属性 public class PropertyValue {private String name;private String ref;private String value; // 赋值的属性为基本数据类型及String类型数据public PropertyValue() {}public PropertyValue(String name, String ref, String value) {this.name name;this.ref ref;this.value value;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getRef() {return ref;}public void setRef(String ref) {this.ref ref;}public String getValue() {return value;}public void setValue(String value) {this.value value;} }2MutablePropertyValues类 一个bean标签可以有多个property子标签所以再定义一个MutablePropertyValues类用来存储并管理多个PropertyValue对象。 import java.util.ArrayList; import java.util.Iterator; import java.util.List;// 用户存储和管理多个PropertyValue对象 public class MutablePropertyValues implements IterablePropertyValue {// 定义List集合对象用来存储PropertyValue对象private final ListPropertyValue propertyValueList;public MutablePropertyValues() {this.propertyValueList new ArrayListPropertyValue();}public MutablePropertyValues(ListPropertyValue propertyValueList) {this.propertyValueList (propertyValueList ! null ? propertyValueList : new ArrayListPropertyValue());}// 获取所有的PropertyValue对象返回以数组的形式public PropertyValue[] getPropertyValues() {// 将集合转换为数组并返回return propertyValueList.toArray(new PropertyValue[0]); // 参数指定返回数组的类型}// 根据name属性值名称获取对应的PropertyValue对象public PropertyValue getPropertyValue(String propertyName) {// 遍历集合对象for (PropertyValue pv : propertyValueList) {if (pv.getName().equals(propertyName)) {return pv;}}return null;}// 判断集合是否为空public boolean isEmpty() {return propertyValueList.isEmpty();}// 添加PropertyValue对象public MutablePropertyValues addPropertyValue(PropertyValue pv) {// 遍历并判断集合中存储的PropertyValue对象是否和传递进来的pv重复了for (int i 0; i propertyValueList.size(); i) {// 获取集合中每一个PropertyValue对象PropertyValue currentPv propertyValueList.get(i);// 如果重复了进行覆盖if (currentPv.getName().equals(pv.getName())) {propertyValueList.set(i, pv);//this.propertyValueList.set(i, new PropertyValue(pv.getName(), pv.getRef(), pv.getValue()));return this; // 目的是实现链式编程}}// 遍历完说明没有重复的this.propertyValueList.add(pv);return this; // 目的是实现链式编程}// 判断是否有指定name属性值的对象public boolean contains(String propertyName) {// 如果不等于null说明包含该name的PropertyValue返回true如果等于null说明不包含返回falsereturn getPropertyValue(propertyName) ! null;}// 获取迭代器对象Overridepublic IteratorPropertyValue iterator() {return propertyValueList.iterator();} }3BeanDefinition类 BeanDefinition类用来封装bean信息的主要包含id即bean对象的名称、class需要交由spring管理的类的全类名及子标签property数据。 // 用来封装bean标签数据 public class BeanDefinition {private String id;private String className;private MutablePropertyValues propertyValues; // property子标签的数据public BeanDefinition() {propertyValues new MutablePropertyValues();}public String getId() {return id;}public void setId(String id) {this.id id;}public String getClassName() {return className;}public void setClassName(String className) {this.className className;}public MutablePropertyValues getPropertyValues() {return propertyValues;}public void setPropertyValues(MutablePropertyValues propertyValues) {this.propertyValues propertyValues;} }2、定义注册表相关类 1BeanDefinitionRegistry接口 BeanDefinitionRegistry接口定义了注册表的相关操作定义如下功能 注册BeanDefinition对象到注册表中从注册表中删除指定名称的BeanDefinition对象根据名称从注册表中获取BeanDefinition对象判断注册表中是否包含指定名称的BeanDefinition对象获取注册表中BeanDefinition对象的个数获取注册表中所有的BeanDefinition的名称 import com.aizen.framework.beans.BeanDefinition;// 注册表接口 public interface BeanDefinitionRegistry {// 注册BeanDefinition对象到注册表中void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);// 从注册表中删除指定名称的BeanDefinition对象void removeBeanDefinition(String beanName) throws Exception;// 根据名称从注册表中获取BeanDefinition对象BeanDefinition getBeanDefinition(String beanName) throws Exception;boolean containsBeanDefinition(String beanName);int getBeanDefinitionCount();String[] getBeanDefinitionNames(); }2SimpleBeanDefinitionRegistry类 该类实现了BeanDefinitionRegistry接口定义了Map集合作为注册表容器。 import com.aizen.framework.beans.BeanDefinition;import java.util.HashMap; import java.util.Map;// 注册表接口的子实现类 public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {// 定义一个容器用来存储BeanDefinition对象private MapString, BeanDefinition beanDefinitionMap new HashMapString, BeanDefinition();Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {beanDefinitionMap.put(beanName,beanDefinition);}Overridepublic void removeBeanDefinition(String beanName) throws Exception {beanDefinitionMap.remove(beanName);}Overridepublic BeanDefinition getBeanDefinition(String beanName) throws Exception {return beanDefinitionMap.get(beanName);}Overridepublic boolean containsBeanDefinition(String beanName) {return beanDefinitionMap.containsKey(beanName);}Overridepublic int getBeanDefinitionCount() {return beanDefinitionMap.size();}Overridepublic String[] getBeanDefinitionNames() {return beanDefinitionMap.keySet().toArray(new String[0]);} }3、定义解析器相关类 1BeanDefinitionReader接口 BeanDefinitionReader是用来解析配置文件并在注册表中注册bean的信息。定义了两个规范 获取注册表的功能让外界可以通过该对象获取注册表对象。加载配置文件并注册bean数据。 // 用来解析配置文件的而该接口只是定义了规范 public interface BeanDefinitionReader {// 获取注册表对象BeanDefinitionRegistry getRegistry();// 加载配置文件并在注册表中进行注册void loadBeanDefinitions(String configLocation) throws Exception; }2XmlBeanDefinitionReader类 XmlBeanDefinitionReader类是专门用来解析xml配置文件的。该类实现BeanDefinitionReader接口并实现接口中的两个功能。引入dom4j依赖坐标 !-- dom4j -- dependencygroupIddom4j/groupIdartifactIddom4j/artifactIdversion1.6.1/version /dependencyimport com.aizen.framework.beans.BeanDefinition; import com.aizen.framework.beans.MutablePropertyValues; import com.aizen.framework.beans.PropertyValue; import com.aizen.framework.beans.factory.support.BeanDefinitionReader; import com.aizen.framework.beans.factory.support.BeanDefinitionRegistry; import com.aizen.framework.beans.factory.support.SimpleBeanDefinitionRegistry; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader;import java.io.InputStream; import java.util.List;// XML解析器针对XML配置文件进行解析的类把Bean解析封装为BeanDefinition对象并注册到注册表中 public class XmlBeanDefinitionReader implements BeanDefinitionReader {// 声明注册表对象private BeanDefinitionRegistry registry;public XmlBeanDefinitionReader() {registry new SimpleBeanDefinitionRegistry();}Overridepublic BeanDefinitionRegistry getRegistry() {return registry;}Overridepublic void loadBeanDefinitions(String configLocation) throws Exception {// 使用dom4j进行xml配置文件的解析SAXReader reader new SAXReader();// 通过输入流获取类路径下的配置文件InputStream is XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);Document document reader.read(is);// 根据Document对象获取根标签对象beansElement rootElement document.getRootElement();// 获取根标签下的所有的bean标签对象ListElement beanElements rootElement.elements(bean);// 遍历所有bean标签集合对象获取每一个beanfor (Element beanElement : beanElements) {// 获取bean标签下的id属性class属性property属性String id beanElement.attributeValue(id);String className beanElement.attributeValue(class);// 将id属性和cLass属性封装到BeanDefinition对家中BeanDefinition beanDefinition new BeanDefinition();beanDefinition.setId(id);beanDefinition.setClassName(className);// 获取bean标签下所有的property标签对象ListElement propertyElements beanElement.elements(property);// 创建MutablePropertyValues对象MutablePropertyValues propertyValues new MutablePropertyValues();for (Element propertyElement : propertyElements) {// 获取property标签下的name属性ref属性value属性String name propertyElement.attributeValue(name);String ref propertyElement.attributeValue(ref);String value propertyElement.attributeValue(value);// 封装为PropertyValue对象PropertyValue propertyValue new PropertyValue(name, ref, value);propertyValues.addPropertyValue(propertyValue);}// 将propertyValues对象封装到beanDefinition对象中beanDefinition.setPropertyValues(propertyValues);// 将beanDefinition对象注册到注册表中registry.registerBeanDefinition(id, beanDefinition);}} }4、IOC容器相关类 1BeanFactory接口 在该接口中定义IOC容器的统一规范即获取bean对象。 // IOC容器父接口 public interface BeanFactory {// 根据bean对象的名称获取bean对象Object getBean(String name) throws Exception;// 根据bean对象的名称获取bean对象并进行类型转换T T getBean(String name, Class? extends T clazz) throws Exception; }2ApplicationContext接口 该接口的所以的子实现类对bean对象的创建都是非延时的所以在该接口中定义 refresh() 方法该方法主要完成以下两个功能 加载配置文件。根据注册表中的BeanDefinition对象封装的数据进行bean对象的创建。 import com.aizen.framework.beans.factory.BeanFactory;// 定义非延时加载功能 public interface ApplicationContext extends BeanFactory {// 进行配置文件加载并进行对象创建void refresh() throws Exception; }3AbstractApplicationContext类 作为ApplicationContext接口的子类所以该类也是非延时加载所以需要在该类中定义一个Map集合作为bean对象存储的容器。声明BeanDefinitionReader类型的变量用来进行xml配置文件的解析符合单一职责原则。BeanDefinitionReader类型的对象创建交由子类实现因为只有子类明确到底创建BeanDefinitionReader哪儿个子实现类对象如解析xml配置文件、properties配置文件。 import com.aizen.framework.beans.factory.support.BeanDefinitionReader; import com.aizen.framework.beans.factory.support.BeanDefinitionRegistry; import com.aizen.framework.context.ApplicationContext;import java.util.HashMap; import java.util.Map;// ApplicationContext接口的子实现类抽象类用于立即加载非延时加载 public abstract class AbstractApplicationContext implements ApplicationContext {// 声明解析器变量protected BeanDefinitionReader beanDefinitionReader;// 定义用于存储bean对象的map容器key存储的是bean的id值value存储的是bean对象protected MapString, Object singletonObjects new HashMapString, Object();// 声明配置文件路径的变量protected String configLocation;Overridepublic void refresh() throws Exception {// 加载BeanDefinition对象beanDefinitionReader.loadBeanDefinitions(configLocation);// 初始化beanfinishBeanInitialization();}// bean的初始化private void finishBeanInitialization() throws Exception {// 从注册表里获取BeanDefinition对象BeanDefinitionRegistry registry beanDefinitionReader.getRegistry();String[] beanNames registry.getBeanDefinitionNames();// 进行每一个bean的初始化for (String beanName : beanNames) {// 调用具体子实现类的getBean方法进行bean的初始化getBean(beanName);}} }注意该类finishBeanInitialization()方法中调用getBean()方法使用到了模板方法模式。 4ClassPathXmlApplicationContext类 该类主要是加载类路径下的配置文件并进行bean对象的创建主要完成以下功能 在构造方法中创建BeanDefinitionReader对象因为在父类中声明了在不同子类中具体实现。在构造方法中调用refresh()方法用于进行配置文件加载、创建bean对象并存储到容器中。重写父接口中的getBean()方法并实现依赖注入DI操作。 import com.aizen.framework.beans.BeanDefinition; import com.aizen.framework.beans.MutablePropertyValues; import com.aizen.framework.beans.PropertyValue; import com.aizen.framework.beans.factory.support.BeanDefinitionRegistry; import com.aizen.framework.beans.factory.xml.XmlBeanDefinitionReader; import com.aizen.framework.utils.StringUtils;import java.lang.reflect.Method;// IOC容器的具体子实现类用于加载类路径下的XML格式的配置文件 public class ClassPathXmlApplicationContext extends AbstractApplicationContext {public ClassPathXmlApplicationContext(String configLocation) {// 通过构造方法设置类路径下的配置文件路径this.configLocation configLocation;// 构建解析器对象beanDefinitionReader new XmlBeanDefinitionReader();// 调用refresh方法try {this.refresh();} catch (Exception e) {throw new RuntimeException(e);}}// 根据bean对象的名称id属性值获取bean对象Overridepublic Object getBean(String name) throws Exception {// 判断对象容器中是否包含指定名称的bean对象Object obj singletonObjects.get(name);// 如果包含直接返回即可if (obj ! null) return obj;// 如果不包含需要自行创建获取BeanDefinition对象里面有bean的信息BeanDefinitionRegistry registry beanDefinitionReader.getRegistry();BeanDefinition beanDefinition registry.getBeanDefinition(name);// 不存在与该id属性值一致的bean返回nullif (beanDefinition null) return null;// 若存在该beanDefinition对象则获取bean信息中的className有了全类名通过反射就可以创建对象String className beanDefinition.getClassName(); // com.aizen.service.impl.UserServiceImpl// 通过反射创建对象Class? clazz Class.forName(className);Object beanObj clazz.newInstance(); // UserServiceImpl// 进行依赖注入操作MutablePropertyValues propertyValues beanDefinition.getPropertyValues();for (PropertyValue propertyValue : propertyValues) {// 获取property的属性String propertyName propertyValue.getName();String ref propertyValue.getRef();String value propertyValue.getValue();// ref和value属性只能存在一个判断使用了哪个属性if (ref ! null !ref.isEmpty()) {// 注意property nameuserDao其中name的值应该和属性名setUserDao方法保持一致// 递归获取依赖的bean对象Object bean getBean(ref); // getBean(UserDao)返回userDao对象// 使用自定义工具类StringUtils拼接构造set方法名String methodName StringUtils.getSetterMethodByFieldName(propertyName); // userDao -- setUserDao// 获取所有的方法对象Method[] methods clazz.getMethods();for (Method method : methods) {// 如果该方法是set方法if (method.getName().equals(methodName)) {// 执行setter方法进行依赖注入method.invoke(beanObj, bean); // userServiceImpl.setUserDao(userDao);}}}if (value ! null !value.isEmpty()) {// 使用自定义工具类StringUtils拼接构造set方法名String methodName StringUtils.getSetterMethodByFieldName(propertyName); // 例username - setUsername// 获取method方法Method method clazz.getMethod(methodName, String.class);method.invoke(beanObj, value);}}// 在返回beanObj对象之前将该对象存储到Map容器中singletonObjects.put(name, beanObj);return beanObj;}Overridepublic T T getBean(String name, Class? extends T clazz) throws Exception {Object bean getBean(name);if (bean null) return null;T obj clazz.cast(bean);return obj;} }StringUtils工具类 public class StringUtils {// 私有构造方法private StringUtils() {}// refuserDao -- setUserDao | valueusername - setUsernamepublic static String getSetterMethodByFieldName(String fieldName) {return set fieldName.substring(0, 1).toUpperCase() fieldName.substring(1);} }bean配置中属性ref与value的区别 refvalueref引用已经存在的对象value创建新的对象ref可以引用其他的bean对象value可以赋一些简单类型的值使用ref的时候Spring容器会在引用后进行验证验证当前的xml是否存在引用的bean使用value的时候spring会在容器启动实例化bean的时候进行验证 5、测试运行自定义Spring IOC框架 至此我们已经完成了自定义SpringIoC的所有功能下面来运行测试一下。 先把我们写的项目安装在本地仓库mvn install。 在我们之前的spring_demo项目中引用该自定义的custom_spring依赖并且注释掉之前的Spring的依赖。 将UserController中导入的Spring包删掉改成导入我们自己的包其他的地方不需要修改。 import com.aizen.framework.context.ApplicationContext; import com.aizen.framework.context.support.ClassPathXmlApplicationContext; import com.aizen.service.UserService;// 控制层 public class UserController {public static void main(String[] args) throws Exception {// 创建Spring的容器对象非延时加载ApplicationContext applicationContext new ClassPathXmlApplicationContext(applicationContext.xml);// 从ioc容器对象中获取userService对象UserService userService applicationContext.getBean(userService, UserService.class);//调用userService方法进行业务逻辑处理userService.add();} }在此处打断点Debug模式运行可以看到执行创建IOC容器后初始化加载并创建了bean对象实现了非延时加载。 运行结果可以看到userDao和userService对象都被创建了说明IOC容器创建成功Bean对象初始化并创建成功并且userService调用add方法可以调用userDao的add方法说明依赖注入成功 测试完ref属性注入下面再接着测试一下value属性注入添加如下代码后测试运行。 import com.aizen.dao.UserDao;// 数据访问层实现类 public class UserDaoImpl implements UserDao {private String username;private String password;// 提供set方法进行注入public void setUsername(String username) {this.username username;}public void setPassword(String password) {this.password password;}public UserDaoImpl() {System.out.println(userDao被创建了);}Overridepublic void add() {System.out.println(UserDao... username password);} }?xml version1.0 encodingUTF-8? beans!-- IOC容器管理对象 --bean iduserDao classcom.aizen.dao.impl.UserDaoImplproperty nameusername valuezhangsan/property namepassword value123456//beanbean iduserService classcom.aizen.service.impl.UserServiceImplproperty nameuserDao refuserDao/!-- 依赖注入DI --/bean /beansvalue属性注入String类型成功实现了自定义依赖管理。 6、自定义Spring IOC总结 1使用到的设计模式 工厂模式。这个使用工厂模式 配置文件的方式。单例模式。Spring IOC管理的bean对象都是单例的此处的单例不是通过构造器进行单例的控制的而是spring框架对每一个bean只创建了一个对象。模板方法模式。AbstractApplicationContext类中的finishBeanInitialization()方法调用了子类的getBean()方法因为getBean()的实现和环境息息相关。迭代器模式。对于MutablePropertyValues类定义使用到了迭代器模式因为此类存储并管理PropertyValue对象也属于一个容器所以给该容器提供一个遍历方式。 Spring框架其实使用到了很多设计模式如AOP使用到了代理模式选择JDK代理或者CGLIB代理使用到了策略模式还有适配器模式装饰者模式观察者模式等。 2符合大部分设计原则 自行体会~~(▽) 3整个设计和Spring的设计还是有一定的出入 Spring框架底层是很复杂的进行了很深入的封装并对外提供了很好的扩展性。而我们自定义SpringIOC有以下几个目的 了解Spring底层对对象的大体管理机制。了解设计模式在具体的开发中的使用。以后学习Spring源码通过该案例的实现可以降低Spring学习的成本。 五、设计模式常见相关面试问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/85644.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无锡网知名网站免费建学校网站

关于Portforge Portforge是一款功能强大的轻量级端口混淆工具,该工具使用Crystal语言开发,可以帮助广大研究人员防止网络映射,这样一来,他人就无法查看到你设备正在运行(或没有运行)的服务和程序了。简而言…

网站标题如何写丰都网站建设报价

简介: 基础知识 XML文件格式 XML基本语法 XML属性 练习: C#读取存储XML XML文件存放位置 读取XML文件 练习: 存储修改XML文件 练习: 总结 实践小项目 必备知识点 必备知识点——C#中XML序列化 必备知识点——C#中XML反序列化 必备…

网站如何添加百度统计休闲农庄展示网站

经过几个月的努力,终于基本完成了人人API拥有的所有功能,界面采用仿照人人梦想版5.13制作,其中资源文件也采用人人的APK文件资源,完成的功能及知识点如下:1.通过三种动画仿照出人人引导页的放大切换图片的效果。2.通过重写ViewGroup仿照出人人菜单和其他界面的手势滑动切换效果…

个人网站免费源码邯郸网站建设报价

数组中有一个数字出现的次数超过数组长度的一半&#xff0c;请找出这个数字。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制&#xff1a; 1 < 数组长度 < 50000 思路&#xff1a;…

唐山哪个公司可以建网站网站开发工具怎么改内容

在 gitcode 上配置SSH公钥后&#xff0c;可以通过SSH协议安全地访问远程仓库&#xff0c;无需每次都输入用户名和密码。以下是配置SSH公钥的步骤&#xff1a; 5分钟解决方案 用 OpenSSH公钥生成器 生成 公钥和私钥&#xff0c;私钥文件&#xff08;id_rsa&#xff09;下载&am…

济南英文网站建设管理平台登录界面

文章目录 mybatis-config.xml-配置文件详解说明文档地址:配置文件属性解析properties 属性应用实例 settings 全局参数定义应用实例 typeAliases 别名处理器举例说明 typeHandlers 类型处理器environments 环境environment 属性应用实例 mappers配置 mybatis-config.xml-配置文…

深圳网站设计公司设计深圳网站设计南京

目录 前言 正文 1.Signal Group概念介绍 1.1 Initialization 1.2 Transmission 1.3 Reception 1.4 Notifications

河南建设工程信息网官网首页搜索引擎优化seo信息

前言&#xff1a;因为平时挺少用到多线程的&#xff0c;写游戏时都在用协程&#xff0c;至于协程那是另一个话题了&#xff0c;除了第一次学习多线程时和以前某个小项目有过就挺少有接触了&#xff0c;最近准备面试又怕被问的深入&#xff0c;所以就赶紧补补多线程基础。网上已…

安阳网站设计多少钱哈尔滨建设工程信息网站

折半查找又为二分查找&#xff0c;对待查找的列表有两个要求&#xff1a;1.必须采用顺序存储结构。 2.必须按关键字大小顺序排列。 #include<stdio.h> #define Max 100 typedef struct {int key;int other; }RecordType; typedef struct {RecordType r[Max];int lenght; …

12333社保查询网官网南通网站排名优化

CCIE-LAB-第十五篇-IPV6-BGP+VPN6+RT 实际中,思科只会给你5个小时去做下面的全部配置 这个是CCIE-LAB的拓扑图 问题 翻译: 根据这些要求,将IPV6连接从总部通过SP扩展到laas站点上的giosk VRF。我在rll assign 2001:2710:311:2/64到r3 assign 2001:2710:311:1/64到gl2的RLI和…

dede网站版权信息wordpress 百度地图api插件

文章首发地址&#xff1a; 学一下 (suxueit.com)https://suxueit.com/article_detail/s9UMb44BWZdDRfKqFv22 先上一张&#xff0c;不知道是那个大佬画的图 简单描述一下流程 client-go封装部分 以pod为例 、先List所有的Pod资源&#xff0c;然后通过已经获取的pod资源的最大版…

最近网站不收录开外贸公司的流程及费用

摘要&#xff1a;对于一个大型网站来说&#xff0c;负载均衡是永恒的话题。随着硬件技术的迅猛发展&#xff0c;越来越多的负载均衡硬件设备涌现出来&#xff0c;如F5 BIG-IP、Citrix NetScaler、Radware等等&#xff0c;虽然可以解决问题&#xff0c;但其高昂的价格却往往令人…

怀化做网站如何利用某个软件做一个网站

在5G时代下&#xff0c;电子元器件电商平台的发展策略与应对措施需要考虑以下几个关键因素&#xff1a; 技术产品更新换代&#xff1a; 随着5G技术的普及和应用&#xff0c;电子元器件的需求将发生变化&#xff0c;对于支持5G技术的电子元器件的需求会增加&#xff0c;而对于旧…

商业网站建设者wordpress视频网站上传视频

《计算机与医学.ppt》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《计算机与医学.ppt(22页珍藏版)》请在人人文库网上搜索。1、计算机与医学,北京大学 信息科学技术学院 2008年9月,2/22,计算机在医学方面能做些什么&#xff1f;,在任何一门学科的研究和实践中&#…

北京网站关键词排名公司网页设计与制作教程读书心得

项目简介最近在一个客户现场搞熔边机项目&#xff0c;涉及到收放卷工艺的卷径计算&#xff0c;同时张力控制使用的是摆杆&#xff0c;然后通过PID控制输出辅助转速补偿收卷伺服速度。单一的PID参数不能自动适应卷径变化,如在小卷径200mm下调试整定出的一组PID参数&#xff0c;当…

甘肃金顶建设公司网站三亚房地产网站制作

连接oracle 数据库真麻烦&#xff0c;还是MySQL方便 Oracle Instant Client 这个东西的版本跟oracle的版本是有讲究的&#xff0c;引用文档的说明 Oracle 标准的客户端-服务器网络互操作性允许不同版本的 Oracle 客户端和 Oracle 数据库之间的连接。有关经过认证的配置&#…

杭州平台网站建设wordpress 错误500

一、背景 前段时间帮公司运维小姑娘调整她自己写的页面样式时发现她用了display: flex&#xff0c;我这个后端老古董还不太懂flex&#xff0c;自愧不如啊&#xff0c;所以写篇博客记录学习下。 现在写的前端页面还停留在依赖 display 属性 position属性 float属性的布局方式&…

网站开发调研做网站配什么绿色好看些

肯定有用&#xff0c;练习就是实战。对于刚学习编程的同学&#xff0c;我觉得跟着例子学习&#xff0c;会有很大的进步。至少让你熟悉语法和理解编程的一些技巧。当你能熟练掌握python编程的方法后&#xff0c;你需要学习一些第三方库&#xff0c;python的第三方库很强大。具体…

遵义新蓝外国语学校网站建设网站项目怎么做

独享带宽 独享带宽针对对带宽有较高的要求&#xff0c;其业务的内容和性质决定只有使用独立的带宽资源才能满足品质的需求&#xff0c;而这种只给单独客户使用的带宽资源称为独享带宽. 使用独享带宽&#xff0c;整个带宽资源归属于一个客户 独享带宽的优点是可自由使用带宽量…

网站关停公告怎么做科技公司简介范文

【README】 本文总结了操作系统 对磁盘的4层抽象&#xff0c;并给出了详细介绍的post 链接&#xff1b; 【1】对磁盘的4层抽象 【1.1】对磁盘的第1层抽象 通过盘块号读写磁盘&#xff08;读写多个扇区&#xff09;&#xff1b; 因为磁盘底层操作的单位是扇区&#xff08;51…